所以我有一个字符串并集类型
type S = 'a' | 'b' | 'c';
我想初始化一个S类型的值,同时断言它是S类型的。有了变量,这很容易:
const s1: S = 'a';
const s2: S = 'z'; // error
然而,我只想实例化值本身,沿着'a' as S
的行,但检查'a'
的类型为S
。
确切的用例是,我使用的是一个提供函数f(s: string)
的库,但我想确保在调用它时,我只使用我认为可以的字符串来调用它。由于[afaik]不能从库外缩小签名范围,所以每次使用f
时,我都想做类似f('a' as S)
的事情。
定义我自己的函数g = (s: S) => f(s)
不是一个好的选择,因为实际上f
的签名看起来像f(s: string, t: T)
,其中T
是一个复杂的库定义类型,我甚至不确定它是否被导出。
实现这一目标的最佳方式是什么?
使用字符串类型(TS操场(将外部函数与您自己的函数包装:
const externalFn = <T>(s: string, t: T) => t
type S = 'a' | 'b' | 'c';
const yourFn = (s: S, t: Parameters<typeof externalFn>[1]) => externalFn(s, t)
如果你需要处理一个有多个参数的函数,你可以使用这个答案中的想法(TS游乐场(:
type DropFirst<T extends unknown[]> = T extends [any, ...infer U] ? U : never
const externalFn = <T>(s: string, t: T) => t
type S = 'a' | 'b' | 'c';
const yourFn = (s: S, ...rest: DropFirst<Parameters<typeof externalFn>>) => externalFn(s, ...rest)
我最终制作了一个简单的包装器函数,如下所示:
function ok<T extends string>(s: T): T {
return s;
}
然后我可以像f(ok<S>('a'))
一样使用它,因为在我的情况下,有多个函数和类型需要我进行验证,而制作一个单独的包装函数将是乏味的,并且不可维护。