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.

相关推荐
Martin -Tang44 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发1 小时前
解锁微前端的优秀库
前端
王解2 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁2 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂2 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐3 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成5 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽5 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新6 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_7 小时前
【Linux】多线程(概念,控制)
linux·运维·前端