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.

相关推荐
用户33790448021725 分钟前
HTML5语义化标签详解
前端
唐某人丶28 分钟前
教你如何用 JS 实现一个 Agent 系统(1)—— 认识 Agentic System
前端·人工智能
丘山子33 分钟前
分享链接格式不统一,rel="share-url" 提案试图解决这个问题
前端·面试·html
JustHappy1 小时前
「Versakit攻略」🔥Pnpm+Monorepo+Changesets搭建通用组件库项目和发包流程
前端·javascript·vue.js
紫金龙腾2 小时前
EDGE 、chrome、浏览器显示“由你的组织管理”
前端·chrome·edge
用户66197734585752 小时前
Vue3笔记
前端·vue.js
2401_837088503 小时前
ref 简单讲解
前端·javascript·vue.js
折果4 小时前
如何在vue项目中封装自己的全局message组件?一步教会你!
前端·面试
不死鸟.亚历山大.狼崽子4 小时前
Syntax Error: Error: PostCSS received undefined instead of CSS string
前端·css·postcss
汪子熙4 小时前
Vite 极速时代的构建范式
前端·javascript