第二个参数类型取决于打字稿中的第一个参数

时间:2021-08-01 01:26:23

标签: typescript

好的,所以我需要一些高级的打字稿类型技巧。我有一个带有 2 个参数的函数,但我希望第二个参数类型取决于第一个参数类型。例如,如果我的第一个参数是一个数字,那么我的第二个参数需要是一个字符串,但是如果我的第一个参数是 Record,那么我的第二个参数是一个数字。我知道我可以做一些函数原型重载,但我希望它是动态的,所以它看起来像这样:

type Test = [number, string] | [Record<string, any>, number];

foo<Test>(34, "bar") // ok
foo<Test>({a:34}, 56) // ok
foo<Test>(34, 56) // error
foo<Test>({a:34}, "bar") // error

我没有打字稿方面的高级知识,无法自己解决,所以如果可能的话,我会找你们所有人指导我。

2 个答案:

答案 0 :(得分:1)

您可以使用 tuple types for rest parameters,包括 unions 的此类元组。因此,您可以像这样将 unsigned char 声明为 generic 函数:

foo()

当您将 declare function foo<T extends readonly any[]>(...args: T): void; 指定为 Test 参数时,这会导致您的示例表现得完全一样:

T

如果您不需要 foo<Test>(34, "bar") // ok foo<Test>({ a: 34 }, 56) // ok foo<Test>(34, 56) // error foo<Test>({ a: 34 }, "bar") // error 是通用的,那么您可以硬编码 foo() 其余元组参数:

Test

无论哪种方式都行。 TypeScript 将 unions-of-rest-tuples 视为类似于 overloads,甚至 IntelliSense 中的 quickinfo 也会将它们显示为重载:

declare function bar(...args: Test): void;
bar(34, "bar") // ok
bar({ a: 34 }, 56) // ok
bar(34, 56) // error
bar({ a: 34 }, "bar") // error

Playground link to code

答案 1 :(得分:0)

您可以将第一个参数定义为扩展 T 的泛型类型 number | Record<string, any>,然后将第二个参数类型定义为有条件地依赖类型 T

function foo<T extends number | Record<string, any>>(
  x: T, y: T extends number ? string : number) {
}

Playground