所有对象属性具有不同的键,但具有相同的类型

时间:2019-02-07 04:16:44

标签: typescript object

我有一个对象,仅使用一次,只有三个属性,但是每个属性应为同一类型。以下内容对我有用,但我想知道是否有更有效的方法来声明timingsObject的类型:

  let timingsObject:
     { start: null | string, end: null | string, length: null | string } =
     { start: null, end: null, length: null }

  // ... later on timeingsArray is of string[] type
  timingsObject.start = timingsArray[0];
  timingsObject.end = timingsArray[1];
  timingsObject.length = timingsArray[2];

3 个答案:

答案 0 :(得分:2)

我可以想到两种替代方法。通用类型或预定义类型。

interface IObject<T> {
  start: T
  end: T
  length: T
}

type myType = string | null

interface IObject2 {
  start: myType
  end: myType
  length: myType
}

let timingsObject: IObject<string | null> = { start: null, end: null, length: null }
let timingsObject: IObject2 = { start: null, end: null, length: null }

答案 1 :(得分:1)

可以将形状定义为

interface Timings {
  start: string | null;
  end: string | null;
  length: string | null;
}

但是该设计无法正确表达您的问题。例如,{ start: string, end: null, length: null }在类型级别上是正确的,但是在程序中表示无效状态。

如果要这样做:

if (timingsObject.start) {
  typeof timingsObject.length.toString(); // Compile-type error!
}

我们知道timingsObject.length是一个字符串,但TypeScript不是。在使用timingsObject的任何其他属性之前,需要先将其验证为string

将问题建模为两个状态的总和。第一个是定义明确的:

interface Timings {
    start: string;
    end: string;
    length: string;
}

第二个是它的空等效项。您输入的是一个或另一个,可以表示为:

declare const timings: Empty<Timings> | Timings;

我们如何建模Empty?让我们将其设置为映射类型,将所有内容转换为null

type Empty<T> =
  T extends object
    ? { [K in keyof T]: null }
    : null

declare function isEmpty<T>(argument: T | Empty<T>): argument is Empty<T>;

现在,编译器知道,如果一个属性是一个字符串,那么其他所有属性也都是一个字符串。

if (!isEmpty(timings)) {
  timings.start + timings.end; // Both are known to be strings!
}

此解决方案可能看起来确实可行(确实如此),但它成功地将您的域问题烘烤到了类型系统中。

答案 2 :(得分:0)

由于计时对象的所有属性要么全部都是字符串,要么全部都是伪造的(并且实际上未在此状态下使用),并且由于所有属性都只应用于一个位置,所以我们也可以:

interface Timings {
    start: string;
    end: string;
    length: string;
}

let timings?: Timings; // could also use let timings: Timings | null = null;

// do other things ...

timings = {
    start: "someValue",
    end: "someOtherValue,
    length: "yetAnotherValue"
};