typescript - What type should I use for default arguments that depend on a type parameter?
问题描述
I'm working on testing the validation logic for a form that has mostly simple text fields, but has some fields that have other kinds of values or require extra logic to set their value. I have an overloaded helper function that looks something like this:
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 {/* ... */}
I'm trying to figure out what the type should be for the 2nd and 3rd arguments of testFieldValidation
's implementation. Here are some things I've already tried:
// 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 {/* ... */}
I'd prefer not to use any
if I can get away with it. Anyone have any ideas?
A relevant GitHub issue, but no solutions are proposed: link
解决方案
Overload implementations are fairly loosely typed compared to the call signatures, in that as long as the implementation parameters and return types are at least as wide as the unions of the types in the call signatures, it should work. So the following should type check:
// function implementation
function testFieldValidation<T>(
field: Field,
valueToTry: T | string = '',
setFieldValue: FieldSetter<T> | FieldSetter<string> = defaultStringSetter
): void {/* ... */ }
Whether or not this meets your needs is another story; inside the implementation the compiler will not have any idea that valueToTry
and setFieldValue
will be correlated to each other (e.g., if the first is string
then the latter is definitely FieldSetter<string>
), so you will find yourself either performing redundant checks or type assertions:
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
Speaking of type assertions, that's always a possibility when you know more about the types of things than the compiler does. So, if you want to just tell the compiler that if the default ""
is used then that ""
will definitely be a valid T
, that could work also:
// function implementation
function testFieldValidation<T extends unknown>(
field: Field,
valueToTry = '' as T,
setFieldValue = defaultStringSetter as FieldSetter<T>
): void {/* ... */ }
That might be easier to use inside the implementation, since the necessary assertions have already been done:
setFieldValue(field, valueToTry); // okay
It's up to you which way if any you'd like to go. Hope that helps; good luck!
推荐阅读
- java - Apache POI 管理散点图
- image - 如何在详细视图中显示来自数组的不同照片(来自集合视图)
- git - Git - 本地主机上的新本地分支当前提交?
- angular - 如何将 Angular 8 http 请求返回值保存在变量中?
- ios - 分享 pdf 文件 .Swift
- python - 无法连接到 Browsermob-proxy ProxyServerError
- r - 在 R 中使用 dplyr 汇总函数时不显示小数位
- c - 行内汇编方法使整个程序崩溃
- html - 如何在 tumblr HTML 编辑器 [2019] 上添加段落而不会出错?
- c++ - 将 c++ 类更改为模板