Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript中为primitive type添加名义类型 #45

Open
jiangshanmeta opened this issue Jan 14, 2022 · 2 comments
Open

TypeScript中为primitive type添加名义类型 #45

jiangshanmeta opened this issue Jan 14, 2022 · 2 comments

Comments

@jiangshanmeta
Copy link
Owner

jiangshanmeta commented Jan 14, 2022

在开发中我们通常会遇到各种ID,通常我们会把这些ID的类型标为string或者number。当业务中关联ID比较多的时候,就有可能在需要A的ID的时候传了B的ID,我们过于宽泛的类型标注导致类型系统无法帮助我们找到这个错误。一个思路是使用名义类型。

虽然TypeScript是结构类型而不是名义类型,但是依然可以模拟。其中比较核心的一点就是采用unique symbol,每一个unique symbol都是不同的 ( 有点NaN的味道了 ), 对于primitive type,我们可以使用联合类型为其添加名义类型

type UserId = string & {
  readonly __nominal: unique symbol;
};

type OrderId = string & {
  readonly __nominal: unique symbol;
};

然后我们就会发现,不通ID类型之间是不能随意赋值的:

const userId = 'userId' as UserId
const orderId:OrderId = userId // 类型系统报错

关于这种写法,我们也可以这么理解,这是一类特殊的字符串(数值),但是用TS的类型系统很难描述,比如 “除了某些特性字符串的字符串” “正数” Negated types

type PositiveNumber = number & {
  readonly __nominal: unique symbol;
};

function isPositiveNumber(x: number): x is PositiveNumber {
  return x > 0;
}

function onlyHandlePositiveNumber(num: PositiveNumber) {}
const num = 100;
// 类型报错
// onlyHandlePositiveNumber(num)

if (isPositiveNumber(num)) {
  onlyHandlePositiveNumber(num);
}
@TobiasNickel
Copy link

so cool, using an OR | it behaves very good:
Screenshot 2023-10-31 at 15 59 55

what, is this the solution for the 10 year old nominal type issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants