如何限制传入函数的参数对象中方法的参数取值范围?
抱歉内容较长,希望能清晰传达我的问题与需求
我们现有一个从扁平文件导入数据的查询接口,结构如下:
class CustomerData { getFieldValue(fieldName: string): string {...} }
调用该方法时,约定使用名为CustomerFieldName的枚举作为fieldName参数值,该枚举规模庞大,示例如下:
enum CustomerFieldName { CUST_ID = '1', CUST_NAME = '2', CUST_PH_HOME = '3-1', // ect.. }
注意getFieldValue的fieldName参数类型为string,我们仅将CustomerFieldName枚举作为常量集合使用,传入FOO_BAR这类值不会被拦截(但大概率无法找到对应数据)。
问题在于,我们习惯将整个CustomerData对象传递给大量函数。这是遗留代码库,我不想大幅重构内部逻辑,但调用者无法知晓函数内部会使用哪些fieldName调用getFieldValue,导致测试这类函数时难以Mock。
我不想改变函数与CustomerData交互的底层逻辑(即仍允许调用getFieldValue('...')),但希望通过函数签名向调用者明确该函数会使用哪些CustomerFieldName值。
例如:若函数prepareCustomerInvoice(custData: CustomerData)仅会调用custData.getFieldValue('2')和custData.getFieldValue('3-1'),我希望修改参数类型为类似如下结构:
type CustomerInvoiceArgs = CustomerData & { getFieldValue(fieldName: CustomerFieldName.CUST_ID | CustomerFieldName.CUST_PH_HOME) }
并修改函数签名为:prepareCustomerInvoice(custData: CustomerInvoiceArgs)
这样在prepareCustomerInvoice内部若调用custData.getFieldValue('NOT_1_OR-3-1'),会触发编译错误(IDE红线提示)。
我希望保持调用语义不变(即仍可传入CustomerData类型变量),但函数内部调用该实例的getFieldValue时被限制可用的字段名。
CRice在评论中给出了提示:需要先OmitgetFieldValue再重新定义。但我遇到了新问题:
enum CustomerFieldName { CUST_ID = '1', CUST_NAME = '2', CUST_PH_HOME = '3-1', // ect.. } class CustomerData { getFieldValue(fieldName: string): string { return fieldName } } type OnlyTheseFields = `${CustomerFieldName.CUST_ID | CustomerFieldName.CUST_PH_HOME}` type LimitedFieldCustomerData<T> = Omit<CustomerData, 'getFieldValue'> & { getFieldValue: (index: T) => string } function bar(custData: CustomerData) { custData.getFieldValue(CustomerFieldName.CUST_NAME); } function foo(custData: LimitedFieldCustomerData<OnlyTheseFields>) { custData.getFieldValue(CustomerFieldName.CUST_NAME); // 这里编译错误,符合预期! bar(custData); // 这里编译通过,但bar内部使用了不被允许的字段,这不符合预期 ;}
如代码所示,foo内部调用getFieldValue(CustomerFieldName.CUST_NAME)会触发编译错误,符合预期;但将受限的CustomerData传入bar时,调用处未报错,而bar内部使用了不被允许的字段。
内容的提问来源于stack exchange,提问作者ThaDon

