对于取决于类型参数的默认参数,应使用哪种类型?

Airhogs777

我正在为具有大多数简单文本字段的表单测试验证逻辑,但是其中某些字段具有其他类型的值或需要额外的逻辑来设置其值。我有一个重载的辅助函数,看起来像这样:

type FieldSetter<T> = (field: Field, value: T) => void; // reusable utility functions to set field values

// overload for the most common case: value is a string, value and setter are optional
function testFieldValidation(
  field: Field,
  valueToTry?: string,
  setFieldValue?: FieldSetter<string>
): void;

// overload for the less common case: value is not a string, value and setter are required
function testFieldValidation<T>(
  field: Field,
  valueToTry: T,
  setFieldValue: FieldSetter<T>
): void;

// function implementation
function testFieldValidation(
  field: Field,
  valueToTry = '', // what should this type be? (defaults to string, which is wrong)
  setFieldValue = defaultStringSetter // and what should this type be?
): void {/* ... */}

我试图弄清楚实现的第二个和第三个参数的类型testFieldValidation这是我已经尝试过的一些方法:

// error: '""' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'
// This is just not how type parameters work, see https://github.com/microsoft/TypeScript/issues/21521
// .. though it'd be nice if TS could determine from the overloads that this is safe
function testFieldValidation<T = string>(
  field: Field,
  valueToTry: T = '',
  setFieldValue: FieldSetter<T> = defaultStringSetter
): void {/* ... */}

// error: this signature is incompatible with the first overload
function testFieldValidation(
  field: Field,
  valueToTry: unknown = '',
  setFieldValue: FieldSetter<unknown> = defaultStringSetter
): void {/* ... */}

any如果可以,我宁愿不使用它。谁有想法?

GitHub相关问题,但未提出解决方案:链接

贾卡尔兹

与调用签名相比,重载实现的类型相当宽松,只要实现参数和返回类型至少与调用签名中类型的并集一样宽,它就可以工作。因此,以下应进行检查:

// function implementation
function testFieldValidation<T>(
  field: Field,
  valueToTry: T | string = '',
  setFieldValue: FieldSetter<T> | FieldSetter<string> = defaultStringSetter
): void {/* ... */ }

这是否满足您的需求是另外一个故事。在实现内部,编译器不会有任何想法,valueToTry并且setFieldValue会相互关联(例如,如果第一个string肯定后者,则肯定是相互关联的FieldSetter<string>),因此您会发现自己执行了冗余检查或键入了断言

setFieldValue(field, valueToTry); // error!
// ----------------> ~~~~~~~~~~
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'

setFieldValue(field, valueToTry as T & string); // okay, asserted

说到类型断言,当您比编译器更了解事物类型时,总是有可能的。因此,如果您只是想告诉编译器,如果使用了默认值"",那么那""肯定是有效的T,它也可以工作:

// function implementation
function testFieldValidation<T extends unknown>(
  field: Field,
  valueToTry = '' as T,
  setFieldValue = defaultStringSetter as FieldSetter<T>
): void {/* ... */ }

由于已经完成了必要的断言,因此在实现内部使用起来可能会更容易:

setFieldValue(field, valueToTry); // okay

如果您要走哪种方式,则取决于您。希望能有所帮助;祝好运!

操场上的代码链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章