Ben*_*n M 6 generics type-inference typescript typescript-generics typescript2.0
我有以下示例对象:
let foo: Foo = {
'key1': { default: 'foo', fn: (val:string) => val },
'key2': { default: 42, fn: (val:number) => val },
// this should throw an error, because type of default and fn don't match
'key3': { default: true, fn: (val:string) => val }
}
Run Code Online (Sandbox Code Playgroud)
接口看起来应该是这样的:
interface Foo {
[key: string]: { default: T, fn: (val:T) => any }
}
Run Code Online (Sandbox Code Playgroud)
这当然不起作用,因为没有T定义.
所以我想这样做:
interface FooValue<T> {
default: T;
fn: (val:T) => any;
}
interface Foo {
[key: string]: FooValue<?>
}
Run Code Online (Sandbox Code Playgroud)
但在那里我也被卡住了.因为我无法定义泛型类型FooValue.
如果我FooValue<any>当然使用,那么一切都输入为any.虽然这不起作用.
我想确保类型default和参数类型fn始终相同.
有什么解决方案吗?或者不能这样做?
如何定义Foo<T>为映射类型,如下所示:
interface FooValue<T> {
default: T;
fn: (val: T) => any;
}
type Foo<T> = {
[K in keyof T]: FooValue<T[K]>
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果T是一些普通的对象类型{a: string, b: number, c: boolean},那么它Foo<T>是它的Foo-ized版本:{a: FooValue<string>, b: FooValue<number>, c: FooValue<boolean>}.现在你可以创建一个辅助函数,只有当它可以被推断Foo<T>为某种类型时才接受一个对象文字T:
function asFoo<T>(foo: Foo<T>): Foo<T> {
return foo;
}
Run Code Online (Sandbox Code Playgroud)
此功能,因为打字稿编译器可以做到从映射类型推断,允许它推断T从Foo<T>.这是工作:
let foo = asFoo({
key1: { default: 'foo', fn: (val: string) => val },
key2: { default: 42, fn: (val: number) => val }
});
// inferred as { key1: FooValue<string>; key2: FooValue<number>;}
Run Code Online (Sandbox Code Playgroud)
这是失败的:
let badFoo = asFoo(
key1: { default: 'foo', fn: (val: string) => val },
key2: { default: 42, fn: (val: number) => val },
key3: { default: true, fn: (val: string) => val }
});
// error! Types of property 'key3' are incompatible.
// Type 'boolean' is not assignable to type 'string'.
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.祝好运!
更新:上面的代码假定您可以foo.key1.fn('abc')推断为类型any,因为它FooValue<string>['fn']被定义为返回的函数any.它会从原始对象文字中忘记输出类型.如果你想foo以记住它的性质的返回类型fn的方法,你可以做到这一点稍有不同的辅助函数:
function asFoo<T, F>(foo: F & Foo<T>): F {
return foo;
}
let foo = asFoo({
key1: { default: 'foo', fn: (val: string) => val },
key2: { default: 42, fn: (val: number) => val },
// next line would cause error
// key3: { default: true, fn: (val: string)=>val}
})
const key1fnOut = foo.key1.fn('s') // known to be string
const key2fnOut = foo.key2.fn(123) // known to be number
Run Code Online (Sandbox Code Playgroud)
这很有效.在这种情况下,asFoo()只需验证输入是否Foo<T>为某些输入T,但它不会将输出类型强制转换为a Foo<T>.根据您的使用情况,您可能更喜欢这种解决方案.祝你好运.
| 归档时间: |
|
| 查看次数: |
5292 次 |
| 最近记录: |