Pet*_*dec 2 type-inference typescript typescript-typings union-types
假设有一个联合类型 Thing将类型组合在一起Foo,Bar并Baz具有区分属性tag.
interface Foo {
tag: 'Foo'
foo: string
}
interface Bar {
tag: 'Bar'
bar: number
}
interface Baz {
tag: 'Baz'
baz: boolean
}
type Union = Foo | Bar | Baz
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个映射类型,我将遍历标记Union并使用映射到标记的类型中的相应接口.问题是:是否可以通过其标记值从联合类型中检索类型?
interface Tagged {
tag: string
}
type TypeToFunc<U extends Tagged> = {
// Is it possilbe to retrieve the type for the given tag from the union type?
// What to put in place of the ???
readonly [T in U['tag']]: (x: ???) => string
}
const typeToFunc: TypeToFunc<Union> = {
// x must be of type Foo
Foo: x => `FOO: ${x.foo}`,
// x must be of type Bar
Bar: x => `BAR: ${x.bar}`,
// x must be of type Baz
Baz: x => `BAZ: ${x.baz}`,
}
Run Code Online (Sandbox Code Playgroud)
如果没有,有没有其他方法来实现这种映射?
jca*_*alz 10
在TypeScript v2.7及更早版本中,没有以编程方式执行此操作.以编程方式使用TypeScript构建联合比检查它们更容易.因此,您可以这样做:
interface UnionSchema {
Foo: {foo: string},
Bar: {bar: number},
Baz: {baz: boolean}
}
type Union<K extends keyof UnionSchema = keyof UnionSchema> = {
[P in K]: UnionSchema[K] & {tag: K}
}[K]
Run Code Online (Sandbox Code Playgroud)
现在你可以使用Union像之前,但个别工会成分可以被称为Union<'Foo'>,Union<'Bar'>和Union<'Baz'>.为方便起见,您仍然可以给他们起名字:
interface Foo extends Union<'Foo'> {}
interface Bar extends Union<'Bar'> {}
interface Baz extends Union<'Baz'> {}
Run Code Online (Sandbox Code Playgroud)
然后输入你的函数:
type TypeToFunc<U extends Union> = {
readonly [T in U['tag']]: (x: Union<T>) => string
}
const typeToFunc: TypeToFunc<Union> = {
// x must be of type Foo
Foo: x => `FOO: ${x.foo}`,
// x must be of type Bar
Bar: x => `BAR: ${x.bar}`,
// x must be of type Baz
Baz: x => `BAZ: ${x.baz}`,
}
Run Code Online (Sandbox Code Playgroud)
从TypeScript v2.8开始,将会有一个名为条件类型的功能,它可以在类型系统中提供更多的表现力.你可以写一个像这样的通用联合鉴别器:
type DiscriminateUnion<T, K extends keyof T, V extends T[K]> =
T extends Record<K, V> ? T : never
Run Code Online (Sandbox Code Playgroud)
然后,根据您的原始定义:
interface Foo {
tag: 'Foo'
foo: string
}
interface Bar {
tag: 'Bar'
bar: number
}
interface Baz {
tag: 'Baz'
baz: boolean
}
type Union = Foo | Bar | Baz
Run Code Online (Sandbox Code Playgroud)
你得到了几乎神奇的:
type TypeToFunc<U extends Union> = {
readonly [T in U['tag']]: (x: DiscriminateUnion<Union,'tag',T>) => string
}
Run Code Online (Sandbox Code Playgroud)
这也有效.如果你typescript@next从npm... 安装,你可以试试这个...否则你需要等待.
希望有所帮助; 祝好运!
| 归档时间: |
|
| 查看次数: |
782 次 |
| 最近记录: |