如何将typescript对象中的属性限制为严格定义的属性

时间:2018-02-16 13:24:49

标签: typescript

给出以下代码:

interface t1 {
  prop1: string;
}

interface t2 {
  prop2: string;
}

type ts = t1 | t2;

const t: ts = {
  prop1: 'foo',
  prop2: 'bar'
}

为什么t对象有效?这可能是不允许的,因此t 只能是t1t2,而不能同时为两者?

可以在打字稿操场here上看到代码。

1 个答案:

答案 0 :(得分:3)

如果接口兼容(即它们不具有任何不兼容类型的属性),则Typescript将允许您指定union类型中的任何属性。我们可以定义一个类型,确保对象文字只与其中一个接口兼容,方法是向每个类型的union类型添加其他类型的所有属性,使用never类型:

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];  
type Exclude<T, TExclude> = Partial<Record<Diff<keyof TExclude, keyof T>, never>>
type ts = (t1 & Exclude<t1,t2>) | (t2 & Exclude<t2, t1>);

interface t1 {
    prop1: string;
    prop4: string;
    propCommon: string;
}

interface t2 {
    prop2: string;
    propCommon: string;
}
const t: ts = { prop1: 'foo',prop2: 'bar', propCommon: ''}
const tt2: ts = {prop2: '', propCommon: ''}
const tt1: ts = {prop1: '', propCommon: '', prop4: ''}

对于3种类型,用法是:

type ts = (t1 & Exclude<t1,t2> & Exclude<t1, t3>) 
    | (t2 & Exclude<t2, t1> & Exclude<t1, t3>)
    | (t3 & Exclude<t3, t1> & Exclude<t3, t2>);

我们还可以定义一些辅助类型,使其看起来更好一些:

type Exclusive2<T, TExclude> = T & Exclude<T,TExclude>
type Exclusive3<T, TExclude, TExclude2> = T & Exclude<T,TExclude> & Exclude<T,TExclude2>
type Exclusive4<T, TExclude, TExclude2, TExclude3> = T & Exclude<T,TExclude> & Exclude<T,TExclude2> & Exclude<T, TExclude3>
type ts = Exclusive3<t1, t2, t3> | Exclusive3<t2, t1, t3> | Exclusive3<t3, t2, t1>