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.

相关推荐
家里有只小肥猫17 分钟前
uniApp小程序保存canvas图片
前端·小程序·uni-app
前端大全19 分钟前
Chrome 推出全新的 DOM API,彻底革新 DOM 操作!
前端·chrome
前端小臻1 小时前
关于css中bfc的理解
前端·css·bfc
白嫖不白嫖1 小时前
网页版的俄罗斯方块
前端·javascript·css
HappyAcmen1 小时前
关于Flutter前端面试题及其答案解析
前端·flutter
顾比魁1 小时前
pikachu之CSRF防御:给你的请求加上“网络身份证”
前端·网络·网络安全·csrf
林的快手1 小时前
CSS文本属性
前端·javascript·css·chrome·node.js·css3·html5
肥肠可耐的西西公主2 小时前
前端(AJAX)学习笔记(CLASS 2):图书管理案例以及图片上传
前端·笔记·学习
大胖丫2 小时前
vue 学习-vite api.js
开发语言·前端·javascript
孙桂月2 小时前
ES6相关操作(2)
前端·javascript·es6