首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >TypeScript中的参数类型推断

TypeScript中的参数类型推断
EN

Stack Overflow用户
提问于 2020-12-12 04:50:08
回答 2查看 176关注 0票数 1

我有以下代码:

代码语言:javascript
代码运行次数:0
运行
复制
type Inferred<T> = T extends (...args: (infer UnionType)[]) => any ? UnionType : never

function f(first: 'first', second: 'second', bool: boolean) {}

type T = Inferred<typeof f> // never

我希望推断的类型是联合类型'first' | 'second' | boolean。我知道我可以这样得到它:

代码语言:javascript
代码运行次数:0
运行
复制
type Inferred<T> = T extends (...args: infer A) => any ? A : never

function f(first: 'first', second: 'second', bool: boolean) {}

type T = Inferred<typeof f>[number] // union type

或者等效地:

代码语言:javascript
代码运行次数:0
运行
复制
type Inferred<T> = T extends (...args: infer A) => any ? A[number] : never

function f(first: 'first', second: 'second', bool: boolean) {}

type T = Inferred<typeof f> // union type

为什么第一种方法不起作用?

EN

回答 2

Stack Overflow用户

发布于 2020-12-12 06:24:58

为了回答这个问题,让我们后退一步,从更广泛的角度来看待它。

TypeScript使用相同的语法(即[])用于元组和数组。但它们是明显不同的概念。为了简洁起见,我将在下面的段落中对元组使用() (而不是标准TypeScript的[])。另外,请记住TypeScript中的T[] === Array<T>

按照惯例,元组是固定长度和异构的(可能包含不同类型的值)。(1, "Adam", 42)(number, string, number)类型的元组。

数组通常是同构的(保存相同类型的值),并且具有任意长度。

在TypeScript中,由于联合类型的支持,两者之间的区别略显模糊。当使用T = number | string时,[1, "Adam", 42]也是一个完美的Array<T>。这在没有联合类型支持的语言中是不可能的(并且会导致找到通常类似于anynumber | string的上下界)。

在提供的示例中使用此知识

type Inferred<T> = T extends (...args: (infer UnionType)[]) => any ? UnionType : never

我们可以把它看作是“从Array<T>类型的带参数的函数列表中获取T”。

我们知道:function f(first: 'first', second: 'second', bool: boolean)的参数类型列表是('first', 'second', boolean)

在这一点上,需要实现以下统一(:=:):

('first', 'second', boolean) :=: Array<T>

这样,只要使用('first', 'second', boolean)类型的值,就可以使用Array<T>类型的值。实际上不存在这样的T,因此推断出never

在这里,看起来T = string | boolean甚至T = 'first' | 'second' | boolean是一个解决方案,但是:

代码语言:javascript
代码运行次数:0
运行
复制
type Arr = Array<'first' | 'second' | boolean>
type Tuple = ['first', 'second', boolean]

const a: Arr =  ['first', 'second', true]
const t: Tuple =  ['first', 'second', true]

let a1: Arr = t;
let t1: Tuple = a; // Type error no. 2322
代码语言:javascript
代码运行次数:0
运行
复制
Target requires 3 element(s) but source may have fewer.(2322)

或者在类型级别上:

代码语言:javascript
代码运行次数:0
运行
复制
type TEA = Tuple extends Arr ? true : false // true
type AET = Arr extends Tuple ? true : false // false

这也解释了为什么type Y = Inferred<(a: number, b: number, c: number) => void>会产生number

总而言之,示例中的(infer UnionType)[]似乎不支持推断元组类型,而只支持数组。

免责声明-我不熟悉TypeScript编译器的内部原理,这是我基于常识和直觉来解释这里发生的事情的最好尝试。

票数 1
EN

Stack Overflow用户

发布于 2020-12-12 05:50:42

这是因为有限参数的函数不能扩展(潜在的)无限参数的函数:

代码语言:javascript
代码运行次数:0
运行
复制
// X is false
type X = 
    ((a: string, b: number) => any) extends ((...args: (string | number)[]) => any)
        ? true
        : false;

后两个方法都使用元组类型(['first', 'second', boolean]),它有一个已知的有限长度,这允许它们工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65258444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档