我正在编写一个函数,该函数运行在查找元素的参数列表中。如果找到,函数将去掉名称并返回值,如果没有,则返回默认值。这些值将是number
或string
。我想要一种使用typescript泛型和约束的方法来编译以下内容。
function GetValue<T extends number | string>(datum: string, element: string, defaultValue: T): T {
if (datum.startsWith(element)) {
if (typeof defaultValue === 'number')
return parseInt(datum.substring(element.length)); // error
else if (typeof defaultValue === 'string')
return datum.substring(element.length); // error
}
return defaultValue;
}
我已经排除了任何错误检查代码,例如parseInt
。这将被称为;
console.log(GetValue("abc123", "abc", 456));
console.log(GetValue("abc123", "def", 456));
并期望得到123
和456
。
目前,它在// error
行失败,因为可以用扩展string
或number
但不是string
或number
的类型来调用函数。
如何约束泛型T
,使其被限制为string
或number
(而不是并集string | number
(,然后返回类型与defaultValue
的类型匹配?
显式转换为T,以删除此错误
function GetValue<T extends number | string>(datum: string, element: string, defaultValue: T): T {
if (datum.startsWith(element)) {
if (typeof defaultValue === 'number')
return parseInt(datum.substring(element.length)) as T;
else if (typeof defaultValue === 'string')
return datum.substring(element.length) as T;
}
return defaultValue;
}
github上有一个讨论这个主题的问题。
请看看其他方法:
interface Overloading {
<T extends number>(datum: string, element: string, defaultValue: T): number;
<T extends string>(datum: string, element: string, defaultValue: T): string;
}
const GetValue: Overloading = <T extends number | string>(datum: string, element: string, defaultValue: T) => {
if (datum.startsWith(element)) {
if (typeof defaultValue === 'number')
return parseInt(datum.substring(element.length));
else if (typeof defaultValue === 'string')
return datum.substring(element.length);
}
return defaultValue;
}
const res = GetValue('12', 'sdf', 2) // number
const res = GetValue('12', 'sdf', 'sdf') // string
const res = GetValue('12', 'sdf', ()=>{}) // error
有时最好不要明确定义函数的返回类型。让TS帮你做吧。
我已经将此函数重载用于约束。
更新
TS文档:功能过载
//Let's say you have an enum:
const enum State {
idle = 'idle',
active = 'active',
disable = 'disable'
}
//And you have a function:
// function handleState(state: State, payload: string | number | number[]): void;
// But you have next constraints:
// If state is `active`, payload should be only string
// If state is `idle`, payload should be number
// If state is `disable`, payload shoul be array of numbers number[]
// So let's update our handleState function
function handleState(state: State.active, payload: string): void;
function handleState(state: State.idle, payload: number): void;
function handleState(state: State.disable, payload: number[]): void;
function handleState(state: State, payload: string | number | number[]) {}
handleState(State.active, 2) // Error, active state can't be along with number payload
handleState(State.active, '2') // Ok, active state can be along with string payload
要使箭头函数重载,请考虑接口,就像我的第一个例子一样。
您可以像我一样向重载中添加泛型参数。
这就是你要问的吗?
因为在仿制药的情况下:
interface Overloading {
<T extends number>(datum: string, element: string, defaultValue: T): number
<T extends string>(datum: string, element: string, defaultValue: T): string
}
T是数字或字符串,但不是并集。