繁体   English   中英

typescript 接口条件可选参数

[英]typescript interface conditional optional parameters

我们可以做到这一点:

interface IMyInterface{
    firstname:string  // this means firstname is mandatory

    name:string  // this also means name is mandatory
}

我怎么说, firstnamename是可选的( ? ),取决于是否提供了另一个?

或者,如果这是不可能的,还有什么其他选择?

编辑:这不是Typescript 接口的副本- 可能需要“一个或另一个”属性吗? .

我们不想为每一个可选元素创建一个单独的界面,因为维护、命名和重构会让人头疼,而且不可重用。

这是说“OneOf”这些键的通用方式,您可以在此处使用它:

type EachOfTmp<T> = {// to make OneOf less gross
  [K in Keys<T>]: {
    _: {[X in K]: T[K]};
  }
};

// require only one of the keys
export type OneOf<T> = EachOfTmp<T>[Keys<T>]["_"] & Partial<T>;

const thing1: OneOf<{ a: number; b: number }> = { a: 2 } // valid
const thing2: OneOf<{ a: number; b: number }> = { b: 2 } // valid
const thing3: OneOf<{ a: number; b: number }> = {} // invalid

编辑:哎呀,我忘了我用这个方便的钥匙交易 -

export type Keys<T> = keyof T;
export function Keys<T>(o: T) {
  if (!o) {
    return [];
  }
  return Object.keys(o) as Keys<T>[];
}

另一种方式:

    interface IName {
        name:string 
    }

    interface IFirstName {
        firstname:string 
    }

    let x: IName | IFirstName;
    x = {}; // Error
    x = { name: "" }; // Ok
    x = { firstname: "" }; // Ok
    x = { name: "", firstname: "" }; // Ok

如果IMyInterface有其他需要保留的成员,我想提出一个更通用的 @Catalyst 响应版本。

type EachExpanded<T> = {
    [key in keyof T]: { [subKey in key]: T[key]; }
};

type FixedSubset<T, U> = Pick<T, Exclude<keyof T, U>>;

type AtLeastSubset<T, U> = Pick<T, Extract<keyof T, U>>;

type AtLeaseOne<T, U> = FixedSubset<T, U> & EachExpanded<AtLeastSubset<T, U>>[keyof AtLeastSubset<T, U>];

const example1: AtLeaseOne<{ a: number; b: number; c: string; }, 'a' | 'b'> =
    { a: 3, b: 4, c: '4' } // valid
const example2: AtLeaseOne<{ a: number; b: number; c: string; }, 'a' | 'b'> =
    { a: 1, c: '1' } // valid
const example3: AtLeaseOne<{ a: number; b: number; c: string; }, 'a' | 'b'> =
    { b: 2, c: '2' } // valid
const example4: AtLeaseOne<{ a: number; b: number; c: string; }, 'a' | 'b'> =
    { c: '3' } // invalid

请记住,此响应使用了刚刚发布的 TypeScript 2.8 版中引入的ExcludeExtract关键字。 这些是条件类型的一部分。

在代码中,我们假设类型T是原始类型或接口, U是一组键,其中必须至少存在一个键。

它的工作方式是通过排除需要基于原始类型T实现的属性来创建类型。 这是使用Pick<T, Exclude<keyof T, U>> ,它包含不在U中的所有内容。

然后,创建另一种类型,仅包含其中至少一个必须存在的元素Pick<T, Extract<keyof T, U>>

EachExpanded将每个特殊集的类型存储在同一键下。 例如,如果键'a''b'成为上述示例的有条件可选, EachExpanded创建以下类型:

{
    a: { a: number; };
    b: { b: number; };
}

这将在具有交集运算符的最终类型中使用,因此至少强制存在其中一个。

本质上,对于上面的例子,我们最终会得到以下结果:

{ c: string; } & ({ a: number; } | { b: number; })

你可以这样写。

interface ContactName{
    firstname?: string;
    name: string;
}

interface ContactFirstName{
    firstname: string
    name?: string
}

type Contact = ContactName | ContactFirstName;

并且当您使用 Contact 界面时,姓名或名字都将成为必填项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM