如何声明性地强制执行类型的兼容性?

时间:2017-11-05 17:13:00

标签: typescript

我想强制执行一个(编译时)约束,即T2类型的变量可赋值给T1类型的变量。

如果我有t2类型的值(T2),那么我可以执行以下操作:

const t1: T1 = t2;

有更好的方法吗?最好不必创建额外的运行时实体。

我没有直接在我的应用程序中定义这些类型中的任何一种,因此我不能将其中一种类型作为其他类型的超类。

2 个答案:

答案 0 :(得分:1)

如果T2无法分配给T1而没有在运行时发出任何内容,您是否正在寻找会给您编译错误的见证人?当然,你可以定义这样的东西:

type ExtendsWitness<U extends T, T> = U

并像这样使用它:

type T2Witness = ExtendsWitness<T2, T1>

如果T2可分配给T1,则不会出现任何错误。否则,您将在ExtendsWitness的第一个类型参数上收到错误,指出T2不符合约束T1

以下是一些具体类型的示例:

interface Super {
  foo: string;
  bar: number;
}

interface GoodSub {
  foo: 'a';
  bar: 3;
  baz: boolean;
}

type GoodWitness = ExtendsWitness<GoodSub, Super> // okay

请注意GoodSub未定义为Super,但编译器见证GoodSubSuper的子类型。这是一个坏子类型的例子:

interface BadSub {
  foo: string;
  baz: boolean;
}

type BadWitness = ExtendsWitness<BadSub, Super> // error

编译器无法见证BadSubSuper的子类型,错误会告诉您问题的确切原因:Type 'BadSub' does not satisfy the constraint 'Super'. Property 'bar' is missing in type 'BadSub'.

希望有所帮助;祝你好运!

答案 1 :(得分:0)

我不认为你想要的东西是可以实现的。抱歉这个愚蠢的句子,但只要你不能定义类型的相对性=&gt;你不能定义类型的相对性。

但是,您仍然有以下选项:

  1. 使用any类型只需指定值

    const t1: T1 = <any>t2;
    const t3: T2 = <any>t1;`
    
  2. 具有施法者功能的类似解决方案:

    function toT1(t: T2): T1 {
        return <any>t;
    } 
    
    const t1 = toT1(t2);
    

    优点是您不需要定义t1类型。

  3. 创建一种将两种类型合并为一种

    的类型
    type T3 = T1 | T2;
    
    const t1: T3 = t2;
    

    这解决了赋值问题,但可能导致已经绑定到T1和T2的实体出现一些问题。这可以根据需要在情境中使用

  4. 创建自定义类型后卫:

    interface T1 { a: any; }
    
    interface T2 { b: any; }
    
    function isT1(t: T1 | T2): t is T1 {
        return true;
    }
    
    const t2: T2 = { b: 1 };
    const t1: T1 = isT1(t2) ? t2 : null;
    

    这会一直返回true,因此您可以将变量分配给t1而不会出现任何问题。然而,这仍然是丑陋的。

  5. 我会选择1号方式。它很简单,完全可以满足您的需求。过度工程也很糟糕。