TypeScript 严格别名检查

12

有没有一种方法可以使typescript进行更严格的类型检查,直到每个别名都检查完毕?

我想实现的是定义类型,例如:

type kilograms = number;
type kilometers = number;
type kilogramsPerKilometer = number;

为了确保我不会将错误键入的值放入变量中,例如:

let x: kilograms = 123;
let y: kilometers = 256;
let z: kilogramsPerKilometer = x / y; // Will popup an error here saying that types are incompatible
在这种情况下,它需要显式类型转换:
let x: kilograms = 123;
let y: kilometers = 256;
let z: kilogramsPerKilometer = <number>x / <number>y; // Will downcast `kilograms` and `kilometers` types to `number` and then up-cast types to `kilogramsPerKilometer`
3个回答

8

在寻找有趣的解决方案时,我不知何时失去了这个问题的追踪。新的解决方案更美观,不会影响界面,也不会污染IDE建议列表。

export type Miles = number & { readonly '': unique symbol };
export type Kilograms = number & { readonly '': unique symbol };
export type MilesPerKilogram = number & { readonly '': unique symbol };

var miles: Miles = 3; // error
var kilos: Kilograms = 3; // error
var milesPerKilos: MilesPerKilogram = x / y; // error

var x: Miles = 3 as Miles; // ok
var y: Kilograms = 3 as Kilograms; // ok
var u: MilesPerKilogram = x / y as MilesPerKilogram; // ok

miles = kilos; // error, yey!
kilos = miles; // error, yey!

适用于任何类型


编辑

请注意,您不允许将{ readonly '': unique symbol }部分提取到单独的类型中,因为它会在类型之间共享唯一符号,使它们共享“名称”,这将打败命名类型的目的:

export type Nominal<T> = T & { readonly '': unique symbol };

export type Miles = Nominal<number>;
export type Kilograms = Nominal<number>;
export type MilesPerKilogram = Nominal<number>;

var miles: Miles = 3; // error
var kilos: Kilograms = 3; // error
var milesPerKilos: MilesPerKilogram = x / y; // error

var x: Miles = 3 as Miles; // ok
var y: Kilograms = 3 as Kilograms; // ok
var u: MilesPerKilogram = x / y as MilesPerKilogram; // ok

miles = kilos; // ok, but it should be error! <================= This is due to declaration of Nominal<T>

请参考https://basarat.gitbook.io/typescript/main-1/nominaltyping以获取更多信息。


1
有趣的技巧,谢谢你提供它! :) - M'λ'

4

目前TypeScript中没有名义上的类型检查(还不支持)https://github.com/Microsoft/TypeScript/issues/202

这是使用区分联合类型的已知解决方案:

interface kilograms {
  kind: "kilograms";
  value: number;
}

interface kilometers {
  kind: "kilometers";
  value: number;
}

function kilosPerKiloms(x: kilograms, y: kilometers): kilogramsPerKilometer {
  return x.value / y.value;
}

const x = { kind: "kilograms", value: 123 };
const y = { kind: "kilometers", value: 256 };
const z = kilosPerKiloms(x, y);
// const z = kilosPerKiloms(y, x); // => error

更多信息在这里:

https://www.typescriptlang.org/docs/handbook/advanced-types.html

https://basarat.gitbooks.io/typescript/content/docs/types/discriminated-unions.html

这些链接提供了有关高级类型和区分联合类型的详细信息。

2

谢谢你给它命名!我正需要这个。 - guillemus
@guillemus 除此之外,您还可以寻找“品牌类型”以获取更多实现。 - nikeee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接