【问题标题】:Why do I get a type inference error in this example and how to do it better?为什么在此示例中会出现类型推断错误以及如何做得更好?
【发布时间】:2020-06-28 11:07:06
【问题描述】:

在下面的打字稿示例中,我有一个函数getPerson,它只需要一个对象和一个键来查找值。但是输入对象是部分泛型:

export type Person = {
    name: string;
    age: string;
}

export type People = Record<string, Person>;

function getPerson<D extends People>(partialData: Partial<D>, key: string): Person {

    if (!partialData.hasOwnProperty(key)) {
        throw new Error("key not found in dataContainer.incompleteDataSet");
    }

    return partialData[key]; // TS Lint Error here
}

此代码似乎可以按我的意愿工作,但是我在 return 语句中收到 TS Lint 错误:

TS2322: Type 'D[string] | undefined' is not assignable to type 'Person'.
  Type 'undefined' is not assignable to type 'Person

在函数getPerson 中,Generic D 应该指定我们拥有什么样的People,例如D 可以是带有 momdad 键的 Parents 类型。

export type Parents = {    
    mom: Person,
    dad: Person,    
}

const parentsData: Partial<Parents> = {
    mom: {
        name: "Ann",
        age: "55",
    }
}
const mom: Person = getPerson(parentsData, "mom");
console.log(mom);

但是getPerson 也应该开放以与其他人结构一起使用,如下所示:

const grandParentsData: Partial<Grandparents> = getGrandParentsData(); 
const grandma: Person = getPerson(grandParentsData, "grandma");

我发现表达这一点的最佳方式是 &lt;D extends People&gt; 旁边的 getPerson。不过,这可能会导致我的 linting 问题,因为D 将被允许拥有其他键值,而不仅仅是&lt;string, Person&gt; 中定义的People。我对吗?您有什么想法可以更好地做到这一点吗?

我正在寻找的不是构建数据的更好方法,而是改进getPerson。 (在我的真实项目中,现在不可能更改数据结构)。

这是TypeScript Playground的链接。

非常感谢!

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    partialData.hasOwnProperty 不充当类型保护。 (原则上也不能作为一个,因为key是动态的)

    最简单的解决方案是使用非空断言:

    function getPerson<D extends People>(partialData: Partial<D>, key: string): Person {
        if (!partialData.hasOwnProperty(key)) {
            throw new Error("key not found in dataContainer.incompleteDataSet");
        }
        return  partialData[key]!;
    }
    

    Playground Link

    你可以得到一个完全类型化的版本,但是它的语义有点不同:

    function getPerson<D extends People>(partialData: Partial<D>, key: string): Person {
        const value = partialData[key]
        if (!value) {
            throw new Error("key not found in dataContainer.incompleteDataSet");
        }
        return value;
    }
    

    Playground Link

    以上版本测试属性的值是否未定义。事实上,这似乎是一种更安全的行为,因为仅仅因为对象具有属性,并不意味着它不是 undefined({ age: undefined }).hasOwnProperty ("age") 是真的,但 ({ age: undefined })['age'] 是未定义的)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多