173. 标签

极难0

尽管 TypeScript 中的结构化类型系统非常强大,但有时使用标签标记一些类型会更方便,以便这些标签不会干扰将这些类型的值互相赋值的能力。

例如,使用标签,您可以检查某个值是否通过了所需函数的调用,并且是按正确的顺序调用的:

const doA = <T extends string>(x: T) => {
  const result = x

  return result as Tag<typeof result, 'A'>
}

const doB = <T extends string>(x: T) => {
  const result = x

  return result as Tag<typeof result, 'B'>
};

const a = doA('foo')
const b = doB(a)

type Check0 = IsTrue<HasTags<typeof b, ['A', 'B']>>

编写一个函数 Tag<B, T extends string>,该函数接受一个除 nullundefined 之外的类型 B,并返回一个带有字符串字面量类型 T 的标记类型。

标记的类型必须与原始类型彼此可互相赋值:

declare let x: string
declare let y: Tag<string, 'A'>

x = y = x

当给已经标记过的类型添加标签时,必须将新的标签添加到标签列表的末尾:

type T0 = Tag<{ foo: string }, 'A'>
type T1 = Tag<T0, 'B'>

type Check1 = IsTrue<HasExactTags<T1, ['A', 'B']>>

添加一些函数来检查类型标签。

GetTags<B> 用于检索类型 B 所有标签的列表:

type T2 = Tag<number, 'C'>

type Check2 = IsTrue<Equal<GetTags<T2>, ['C']>>

HasTag<B, T extends string> 用于检查类型 B 是否带有标签 T(并返回 truefalse):

type T3 = Tag<0 | 1, 'D'>

type Check3 = IsTrue<HasTag<T3, 'D'>>

HasTags<B, T extends readonly string[]> 用于检查类型 B 是否依次带有标签元组 T 中的标签:

type T4 = Tag<Tag<Tag<{}, 'A'>, 'B'>, 'C'>

type Check4 = IsTrue<HasTags<T4, ['B', 'C']>>

HasExactTags<B, T extends readonly string[]> 用于检查类型 B 的所有标签的列表是否严格等于标签元组 T

type T5 = Tag<Tag<unknown, 'A'>, 'B'>

type Check5 = IsTrue<HasExactTags<T5, ['A', 'B']>>

最后,添加类型 UnTag<B>,该类型用于去除类型 B 所有的标签:

type T6 = Tag<{ bar: number }, 'A'>
type T7 = UnTag<T6>

type Check6 = IsFalse<HasTag<T7, 'A'>>
评论(0)
题库

TypeScript

加载中...