NoInfer: TypeScript 5.4'的新类型 (翻译)

今天看到一篇关于 noInfer 的文章,特此翻译过来,原文链接 www.totaltypescript.com/noinfer


TypeScript 在5.4版本带来了 NoInfer 新类型,让我们看看它是如何提高在ts在具体条件下的推导能力

TypeScript 5.4 brought a new utility type called NoInfer. Let's see how it can be used to improve TypeScript's inference behavior in certain situations.

什么是NoInfer

NoInfer是一种可以用来阻止ts从泛型函数内部推导能力的类型

NoInferis a utility type that can be used to prevent TypeScript from inferring a type from inside a generic function.

我们稍后会考虑为什么会这么做,首先我们看一下他是如何工作的

We'll look at why you'd want to do this in a moment. But first, let's see it at work

想象一下我们有一个只返回形参类型的泛型函数

Imagine we have a generic function that just returns the type of the value passed in:

ts 复制代码
const returnWhatIPassedIn = <T>(value: T) => value;
// hello
const result = returnWhatIPassedIn("hello");

在这个条件下,ts 推断出 result 类型是 hello

In this case, TypeScript infers the type of result to be "hello".

但是如果我们使用 NoInfer 包裹呢

But what if we were to wrap value: T with NoInfer?

ts 复制代码
const returnWhatIPassedIn = <T>(value: NoInfer<T>) => value;

// unknow
const result = returnWhatIPassedIn("hello");

NoInfer 阻止了value 从 T 推断出的类型,所以,result 被推断出是 unknown,我们必须显式的提供类型给returnWhatIPassedIn 才能获得想要获取的类型

NoInfer has prevented value from being a valid source of inference for T. So now, result is inferred as unknown. We'd need to explicitly provide the type to returnWhatIPassedIn to get the desired return type:

ts 复制代码
const result = returnWhatIPassedIn<"hello">("hello");

所以,为什么你想要这么做呢?

So, why would you want to do this?

NoInfer 可以解决的问题

想象一下,有一个函数,它有多个变量可以从一个类型推导出来

Let's imagine that you have a function that has multiple candidates for inferring a type parameter.

举一个例子,一个函数创建了一个有限状态机(FSM),这个FSM 有一个 initial 状态和一个 states 列表,这个 initial 必须是 states 的一员

A great example is a function that creates a finite state machine (FSM). The FSM has an initial state and a list of states. The initial state must be one of the states.

让我们使用 declare 去定义函数声明(这样我不用提供实现)

Let's use declare to define the function signature (so I don't have to provide an implementation):

ts 复制代码
declare function createFSM<TState extends string>(config: {
  initial: TState;
  states: TState[];
}): TState;

注意到,有两处地方可能倒推出 TState 类型: initialstates

Notice that there are two possible places where TypeScript could infer the type TState from: initial and states.

如果我们调用他,ts 会从 initialstates 两处推断

If we try to call it, TypeScript will infer TState from BOTH initial and states:

ts 复制代码
const example = createFSM({
  initial: "not-allowed",
  states: ["open", "closed"],
});

// const example: "not-allowed" | "open" | "closed"
console.log(example);

但是这是一个问题,我们只想从 states 推断出 TState 类型,我们不想从 inital 推断类型,我们想要确保 initalstates 数组中

But this is a problem! We want TypeScript to infer TState from states only. We don't want initial to be a candidate for inference. We want to ensure that initial is a valid state in the states array.

NoInfer 如何帮助解决

我们可以使用 NoInfer 去阻止 initial 作为推断候选

We can use NoInfer to prevent initial from being a candidate for inference

ts 复制代码
declare function createFSM<TState extends string>(config: {
  initial: NoInfer<TState>;
  states: TState[];
}): TState;

现在,我们调用 createFSM, ts 只会从 states 中推导出 TState 类型,意味着我们正确的从 initial 属性中获取了一个错误

Now, when we call createFSM, TypeScript will infer TState from states only. This means that we correctly get an error from our initial property:

ts 复制代码
createFSM({
  initial: "not-allowed",
  //Type '"not-allowed"' is not assignable to type '"open" | "closed"'.
 states: ["open", "closed"],
});

如果你使用 NoInfer 包裹 statesstates 只会有一个有效值,那就是 initial

If we swap NoInfer over to states, then the only valid states will be the value of initial:

ts 复制代码
declare function createFSM<TState extends string>(config: {
  initial: TState;
  states: NoInfer<TState>[];
}): TState;

createFSM({
  initial: "open",
  states: ["closed"],
  // Type '"closed"' is not assignable to type '"open"'.
});

所以,我们可以使用 NoInfer 来控制 ts 从函数内部泛型类型,当有多个运行时参数,每个参数都引用相同的类型参数时,这可能很有用。NoInfer 允许你控制ts应该从哪个参数进行推断

So, we can use NoInfer to control where TypeScript infers a type from inside a generic function. This can be useful when you have multiple runtime parameters each referencing the same type parameter. NoInfer allows you to control which parameter TypeScript should infer the type from.

相关推荐
zwjapple34 分钟前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20203 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem3 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊3 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术4 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing4 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止4 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall4 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴4 小时前
简单入门Python装饰器
前端·python
袁煦丞5 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作