我有一个函数,该函数接收带有options
属性的kind
自变量。 kind
的可能值是一小组值。所以基本上是一个枚举。
取决于kind
的函数应该具有不同的返回值。虽然所有可能的返回值都从某种常见的基本类型扩展而来。
我可以通过重载实现我想要的功能,但是函数本身的类型不是很好:
function test(options: Scenarios['bar']['options']): Scenarios['bar']['ret'];
function test(options: Scenarios['foo']['options']): Scenarios['foo']['ret'];
function test(options: any): any {
...
};
是否有使用泛型键入此内容的好方法? if(options.kind === 'foo') { return ... }
还将正确地强制使用正确的返回类型将是完美的。
那是我尝试过的,但是没有用。
type Base {
a: string;
}
type Foo {
b: string;
}
type Bar {
c: string;
}
interface Scenarios {
foo: { options: { kind: 'foo', input: string }, ret: Foo },
bar: { options: { kind: 'bar' }, ret: Bar },
}
function test<S extends keyof Scenarios, O extends Scenarios[S]['options'], R extends Scenarios[S]['ret']>(options: O): R {
const out: Partial<R> = {
a: 'one',
};
if(options.kind === 'foo') {
out.b = options.input;
}
if(options.kind === 'bar') {
out.c = "whatever"
}
return out;
}
这里O
和R
似乎都没有正确输入。我收到多个错误:
a: 'one',
错误可能仅指定了已知的属性,而'Part'类型的'a'不存在options.input
错误不存在。 out.b
(和out.c
)错误在“部分”类型上不存在。答案 0 :(得分:1)
我并不是这个领域的专家,但是经过您的请求一段时间后,我意识到了一些事情:
这就是我想出的一个解决方案:
type Base = { // I'm assuming this is the base type for Foo and Bar
a: string;
}
interface Foo extends Base { // so I shall modify here a bit
b: string;
}
interface Bar extends Base { // and here of course
c: string;
}
interface Scenarios {
// Now I put the return type inside the option, to make the discrimination work
// Of course, I need to make 'ret' optional, or your input won't make sense
foo: { kind: 'foo', input: string, ret?: Foo },
bar: { kind: 'bar', ret?: Bar },
}
// Notice the use of 'Required' here; that brings the actual type of 'ret' back
function test<X extends keyof Scenarios>(options: Scenarios[X]): Required<Scenarios[X]>['ret'] {
let data = options as Scenarios[keyof Scenarios]; // create a union type
data.ret = { a: 'one' } as Scenarios[keyof Scenarios]['ret']; // type assertion
if (data.kind === 'foo') {
data.ret!.b = data.input; // finally the discrimination works!
}
if (data.kind === 'bar') {
data.ret!.c = "whatever"
}
return data.ret!;
}
好吧,到目前为止,很好,不幸的是,我仍然无法使TypeScript自动推断通用参数。说如果我跑步:
var result = test({ kind: 'foo', input: "aas" }); // oops
然后TypeScript仍然无法确定result
的类型为Foo
。但是,当然,这种自动推断的实用价值非常低,因为即使有效,它也只有在您在函数的参数中按字面意思键入“ foo”时才有效,并且如果可以,是什么让您无法键入通用参数?
您可以在此Playground Link
中尝试这些代码我刚刚找到了我上一个问题的解决方案:
function test<X extends keyof Scenarios>(options: { kind: X } & Scenarios[X]): Required<Scenarios[X]>['ret'] {
....
}
var result = test({ kind: 'foo', input: "aas" }); // It works!
技巧是将{ kind: X }
添加到参数声明中。
请参阅此Playground Link。