如何优化打字稿中对象的属性值?

时间:2019-06-05 15:41:11

标签: typescript

有什么方法可以改善对象的属性?

declare const a: {
  x?: number
};

if (a.x) {
  doSomething(a); // how do I refine `a.x` here to `number`?
}

我了解了原因,并且知道可以将a.x分配给const,但是我想传递整个a对象并告诉TS a.x不再可能undefined

3 个答案:

答案 0 :(得分:3)

对于通用解决方案,这是对@AlekseyL。的建议的轻微调整:

function has<T extends {}, K extends keyof T>(a: T, k: K): a is T & { [k in K]-?: T[K] } {
  return typeof a[k] !== "undefined";
}

declare const a: {
  x?: number
};

if (has(a, "x")) {
  doSomething(a);
}

Even More Generic™解决方案:

function has<T extends object, K extends keyof T>(
  obj: T,
  ...props: K[]
): obj is T & { [k in K]-?: NonNullable<T[K]> } {
  for (const prop in props) {
    if (obj[prop] === null || obj[prop] === undefined) return false;
  }

  return true;
}

答案 1 :(得分:2)

您可以为此使用type guard

declare const a: {
  x?: number
};

if (hasX(a)) {
  doSomething(a); // a is of type { x: number } here
}

function hasX(a: { x?: number }): a is { x: number } {
  return !!a.x;
}

Playground

答案 2 :(得分:2)

部分类型

最简单的方法是使用Partial type。它允许您将现有类型映射到相似的类型,并将所有属性标记为可选。

然后,当您调用doSomething时,告诉打字稿,现在a可以通过强制转换视为完整项目。

interface Item {
  x: number
}

const a: Partial<Item> = {};

if (a.x) {
  doSomething(a as Item);
}

function doSomething(item: Item) { /* ... */ }

这将告诉打字稿将“ a”作为“部分项”来引用。

使用带有部分防护的类型防护

如果您想避免在最后使用强制转换,并使用打字稿机制来了解a是完整类型,则可以使用Type Guard。这样,您无需告诉打字稿对待a as Item

interface Item {
  x: number
}

const a: Partial<Item> = {};

if (isItemComplete(a)) {
  doSomething(a);
}

function doSomething(item: Item) { /* ... */ }

function isItemComplete(item: Partial<Item>): item is Item {
  return !!item.x; // <-- make sure everything exists on item
}

当我们在isItemComplete中调用if时,打字稿知道:在if范围内,a绝对是完整的{ {1}},而不是Item。在该Partial<Item>之外,打字稿将继续将if视为a