使用TypeScript中的基本类型创建唯一类型?

Nim*_*mai 6 typescript

我想给类对象提供唯一的id类型,即使它们都是字符串.我尝试使用type,我尝试从具有唯一子类名称的基类派生.

请参阅以下示例.既不typeextends不允许我指示编译器将它们视为唯一类型.我仍然可以将HumanId传递给期望AnimalId的函数,反之亦然.

我认为它们是对象兼容的,从底层的JavaScript角度来看,这是完全有道理的.事实上,如果我向AnimalId添加一个唯一的成员,我会得到我期望的错误:

Argument of type 'HumanId' is not assignable to parameter of type 'AnimalId'.

使用TypeScript有一个很好的方法来为基本类型创建唯一类型别名吗?

// type HumanId = string;
// type AnimalId = string;

class id {
    constructor(public value: string) { }
    toString(): string { return this.value;}
}
class HumanId extends id { };
class AnimalId extends id { };

function humanTest(id: HumanId): void {

}

function animalTest(id: AnimalId): void {

}

let h: HumanId = new HumanId("1");
let a: AnimalId = new AnimalId("2");

animalTest(h);
Run Code Online (Sandbox Code Playgroud)

blu*_*e10 15

我遇到了这个问题,但我的用例有一个小小的转变:我想为number. 想象一个 API,其中有例如hours: numberminutes: numberseconds: number等,但您希望类型系统强制正确使用所有单位。

@Evert 提到的博客文章在这方面是一个很好的资源。这个想法是用一些从未实际使用过的虚拟对象创建一个交叉类型。创建新的唯一类型可以通过通用帮助器类型进行抽象。举例说明:

// Generic definition somewhere in utils
type Distinct<T, DistinctName> = T & { __TYPE__: DistinctName };

// Possible usages
type Hours = Distinct<number, "Hours">;
type Minutes = Distinct<number, "Minutes">;
type Seconds = Distinct<number, "Seconds">;

function validateHours(x: number): Hours | undefined {
  if (x >= 0 && x <= 23) return x as Hours;
}
function validateMinutes(x: number): Minutes | undefined {
  if (x >= 0 && x <= 59) return x as Minutes;
}
function validateSeconds(x: number): Seconds | undefined {
  if (x >= 0 && x <= 59) return x as Seconds;
}
Run Code Online (Sandbox Code Playgroud)

f(h: Hours, m: Minutes, s: Seconds)现在不能仅使用 any 来调用函数number,但可以确保完全类型安全。另请注意,该解决方案没有内存/运行时开销。

实际上,这种方法对我来说效果很好,因为这些“不同”类型可以在number需要的地方隐式使用。as Hour只有反过来才需要通过eg 进行显式转换。一个小缺点是像这样的表达式hours += 1需要替换为hours = (hours + 1) as Hours. 正如博客文章中所演示的,其好处通常会超过稍微更明确的语法。

旁注:我之所以命名为泛型类型,Distinct是因为这个名称对我来说更自然,这就是Nim编程语言中该功能的调用方式。


Sar*_*ana 4

正如您所提到的,这些类型在结构上是兼容的。使它们独一无二的唯一方法是为其添加独特的属性。

如果您只想编译器区分两者,您可以添加虚拟唯一成员,这不会产生运行时差异:

class HumanId extends id {
  private _humanId: HumanId; // Could be anything as long as it is unique from the other class
}
class AnimalId extends id {
  private _animalId: AnimalId;
}
Run Code Online (Sandbox Code Playgroud)

  • 是的。感谢您确认我没有错过任何语言功能。我认为能够声明“type HumanId = unique string”会很好。某种方式可以利用编译时检查基本类型以用于特定目的。 (2认同)
  • 为了扩展这一点,所提出的方法只是其他几种方法之一。TypeScript Deep Dive 书中有一整节关于此类问题的章节,称为名义类型:https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html (2认同)