我有一个接收 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',
对象字面量错误可能仅指定已知属性,并且类型“部分”中不存在“a”options.input
类型“O”上不存在属性“输入”的错误。 out.b
(和 out.c
)类型“部分”上不存在属性“b”的错误。 最佳答案
我不是这方面的专家,但在根据您的要求玩了一段时间后,我意识到了一些事情:
话虽如此,这是我想出的解决方案:
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
.但是,当然,这种自动推理的实际值(value)非常低,因为即使它有效,它也只有在您在函数的参数中逐字键入“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 .
关于typescript - 如何根据输入参数键入返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61368548/