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.

相关推荐
努力的小郑13 分钟前
今晚Cloudflare一哆嗦,我的加班计划全泡汤
前端·后端·程序员
q***64971 小时前
头歌答案--爬虫实战
java·前端·爬虫
凌波粒1 小时前
SpringMVC基础教程(4)--Ajax/拦截器/文件上传和下载
java·前端·spring·ajax
液态不合群2 小时前
DDD驱动低代码开发:从业务流程到领域模型的全链路设计
前端·低代码·架构·ddd
jonyleek2 小时前
JVS低代码开发中,如何创建自定义前端页面并接入到现有系统中,从创建到接入的全攻略
前端·低代码·前端框架·软件开发
谢尔登2 小时前
【React】React组件的渲染过程分为哪几个阶段?
前端·javascript·react.js
MediaTea2 小时前
Python 第三方库:Flask(轻量级 Web 框架)
开发语言·前端·后端·python·flask
5***o5002 小时前
前端构建工具缓存清理,解决依赖问题
前端·缓存
lcc1873 小时前
Vue Vue与VueComponent的关系
前端·vue.js
无敌最俊朗@3 小时前
Vue 3 概况
前端·javascript·vue.js