测试映射类型

时间:2019-05-06 15:07:06

标签: typescript unit-testing types

回答了question,我不得不测试复杂的映射类型SelectorResult。我使用了两种测试:

  • 单元测试:可自动化,但基于限于测试类型的值
  • 手动检查类型别名:SelectorResult<{ a: 'invalid' }>是否由TypeScript编译器进行并具有预期的输出(此处为{})?

是否可以使用TypeScript编写自动类型测试,例如TypeScript编译器警告我们有关意外类型的信息?

1 个答案:

答案 0 :(得分:0)

这是我自己解决此问题的尝试。

我想到的解决方案不是很好,但是可以利用TypeScript编译器来检查计算的类型。提示是要调用两次函数checkExtends<A, B extends A>()checkExtends<Expected, Actual>(); checkExtends<Actual, Expected>();来检查ActualExpected这两种类型在结构上是否严格兼容。

我已经创建了一种计算类型PropDiff<A, B>(请参见最后),以帮助发现类型差异,并列出:

  • A中不是B的键:{ [k]: { left: A[k] } }
  • B中不是A的键:{ [k]: { right: B[k] } }
  • 具有相同键但值类型不同的属性:{ [k]: { left: A[k], right: B[k] } }

最终模式由5行组成:

type TestN_Actual   = TBD;
type TestN_Expected = TBD; 
type TestN_Differ   = PropDiff<TestN_Actual, TestN_Expected>;
checkExtends<TestN_Expected, TestN_Actual>();
checkExtends<TestN_Actual, TestN_Expected>();

示例:

type Test2_Actual   = { a: 1 } & {};
type Test2_Expected = { a: number }; 
type Test2_Differ   = PropDiff<Test2_Actual, Test2_Expected>;
checkExtends<Test2_Expected, Test2_Actual>();
checkExtends<Test2_Actual, Test2_Expected>(); // Error for 'Test2_Expected': "Types of property 'a' are incompatible..."

助手代码:

type Diff<T, U> = T extends U ? never : T;

type KeyDiff<A, B> = Diff<keyof A, keyof B>;
type ValDiffKey<A, B> = { [K in keyof A]: K extends keyof B ? A[K] extends B[K] ? B[K] extends A[K] ? never : K : K : never }[keyof A];

type PropDiff<A, B> = {
    [P in KeyDiff<A, B> | KeyDiff<B, A> | ValDiffKey<A, B>]:
        P extends keyof A ?
            P extends keyof B ?
                { left: A[P], right: B[P] } :
                { left: A[P] } :
        P extends keyof B ?
            { right: B[P] } :
            never;
};

function checkExtends<A, B extends A>() {}

用于验证PropDiff<A, B>的示例:

type Test1_Actual = PropDiff<
    { a: 1, b: 2, c: 1, d: 1 },
    { a: number, b: {}, c: 1, e: 1 }>;
type Test1_Expected = {
    a: { left: 1, right: number },
    b: { left: 2, right: {} },
    d: { left: 1 },
    e: { right: 1 }
}; 
checkExtends<Test1_Expected, Test1_Actual>();
checkExtends<Test1_Actual, Test1_Expected>();

Whole code in the TypeScript Playground