不知道中文该叫什么,隐式标称类型
?咳咳,简单来说我们想标记一类特定的对象是某个类型的,但是又没有也不想在他身上加个脏脏的标记字段,如下面的例子:
class Foo {}
class Bar {}
let foo: Foo = new Bar()明明是两个类,但是其中一个的实例居然可以直接赋值成另一个类型。为了不让这么操作,可以要求 Foo 身上有个 Bar 身上没有的东西,可以往他身上添加一个不存在的私有属性来达到目的:
class class FooFoo {
private declare Foo._isFoo: true_isFoo: true
}
class class BarBar {}
let foo: class FooFoo = new constructor Bar(): BarBar()这里有两个标记使得他变得如此好用:
private 决定了它仍然可以产生类型标记,但禁止了上层用户直接访问,你只能通过构造函数来实例化这个特殊的类型:
// 生成的 d.ts
declare class Foo {
private _isFoo
}declare 决定了这个属性只是个标记而没有实体,因此生成的 JavaScript 也很干净:
// 生成的 js
class Foo {}如果你设置了 useDefineForClassFields: false,也可以省略 declare 换成 !。
上文往 class 上添加了私有属性,如果是往 interface 上加呢?诶,我们发现 private 是保不住了,但是可以让一些类共享同一个类型,而且用户一般不会自己尝试实现这个类型:
type type FooLike = {
_isFoo: FooLike;
}
FooLike = { _isFoo: FooLike_isFoo: type FooLike = {
_isFoo: FooLike;
}
FooLike }
class class BarBar {
declare Bar._isFoo: this_isFoo: this
}
let let a: FooLikea: type FooLike = {
_isFoo: FooLike;
}
FooLike = new constructor Bar(): BarBar()
class class UserDefinedUserDefined {}
let b: type FooLike = {
_isFoo: FooLike;
}
FooLike = new constructor UserDefined(): UserDefinedUserDefined()传统 JavaScript 人的做法是存一个 { type: string, value },写起来不免有些繁琐而且不利于代码压缩。我们可以考虑下面这个写法:
class Value<T> {
/** @internal */
constructor(readonly type: Type<T>, readonly value: T) {}
static define<T>() {
return new Type<T>()
}
is<T>(type: Type<T>): this is Value<T> {
return this.type === type
}
}
class Type<T> {
of(value: T): Value<T> {
return new Value(this, value)
}
}
// 定义一个类型叫温度
const temperature = Value<number>.define()
// 实例化这个类型
const a = temperature.of(42)
a.is(temperature) // true注意到 @internal 标记,这使得最终用户不能看到这个构造,也就可以要求一定通过指定的工厂函数实例化自定义类型了。