我已经为此绞尽脑汁有一段时间了,所以我决定在 Stackoverflow 上提出这个问题,希望有人能够帮助我。这是我的问题的简化代码片段版本:TypeScript Playground
type options = "bar" | "foo";
interface barFunctions {
barFunction: () => void;
}
interface fooFunctions {
fooFunction: () => void;
}
interface returnFunctions {
bar: barFunctions,
foo: fooFunctions
}
const example = <T extends options>(options: options): returnFunctions[T] => {
if (options === "bar") {
return {
barFunction() {
console.log("It's the bar function");
}
// I don't expect an error here, the options parameter is set to "bar", so there is no need for a "fooFunction..."
}
}
if (options === "foo") {
return {
fooFunction() {
console.log("It's the foo function");
}
// I don't expect an error here, the options parameter is set to "foo", so there is no need for a "barFunction..."
}
}
throw new Error(`Expected either foo or bar but got ${options}`)
}
解释一下:
我想在 example
上自动完成函数一旦以某个 option
执行参数。
所以如果我输入 example("foo").<autocompletion expects fooFunctions interface>
。所以它会告诉我example("foo").fooFunction()
是唯一的选项,因为第一个函数的参数是“foo”。
如果我输入 example("bar").<autocompletion expects barFunctions interface>
。所以它会告诉我example("bar").barFunction()
是唯一的选项,因为第一个函数的参数是“bar”。
但是现在的问题是,两个返回对象都期望另一个函数在那里,即使我不希望这样......
有 Typescript 专家可以帮助我吗?
最佳答案
有多种方法可以解决这个问题。大多数都不是类型安全的(例如重载或使用类型断言),因为它们无法为编译器提供验证函数实现中的逻辑的方法。
您的通用方法并不遥远。首先要修复的是泛型类型 T
不用于输入参数。让我们为参数 option
指定类型 T
。
const example = <T extends options>(option: T): returnFunctions[T] => {
return {
get bar() {
return {
barFunction() {
console.log("It's the bar function");
},
};
},
get foo() {
return {
fooFunction() {
console.log("It's the foo function");
}
}
}
}[option]
};
现在为了获得我们想要的类型安全,我们必须将函数实现转换为这种映射形状的结构。每个键都是一个getter
,用于推迟每条路径的评估。我们这样做是为了避免每次调用函数时都必须计算所有路径。如果计算这些并不昂贵,这对您来说可能并不重要。
TypeScript 可以验证这个 map 形状的结构是否符合 returnFunctions[T]
类型。
关于基于第一个函数的参数有条件返回函数的 typescript 自动完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75220340/