typescript - 当 T 未定义时如何输入 `K extends keyof T`?

标签 typescript

我想向这个 JS 函数添加 TypeScript 类型:

function getProp(obj, prop) {
  if (!obj) {
    return undefined;
  }

  return obj[prop];
}

如果不需要处理未定义,则可以使用:

function getProp<T, P extends keyof T>(obj: T, prop: P): T[P] {
  // ...
}

但是,对于 undefined,这种使用 | 的幼稚方法未定义不起作用:

function getProp<T, P extends keyof T>(obj: T | undefined, prop: P): T[P] | undefined {
  if (!obj) {
    return undefined;
  }

  return obj[prop];
}

const obj1 = {
  id: 1,
  name: 'obj1',
};
const obj2 = undefined;

getProp(obj1, 'id');
getProp(obj2, 'id');
              ^^^ Argument of type '"id"' is not assignable to parameter of type 'never'.ts(2345)

Playground .

输入此内容的最佳方式是什么?

最佳答案

我想我是否要全力以赴,让 getProp() 函数接受各种 obj 参数,然后允许任何键,如果 obj 可能是未定义,我会这样做:

function getProp<T,
    P extends T extends any ? (undefined extends T ? keyof any : keyof T) : never
>(
    obj: T,
    prop: P
): T extends any ? (P extends keyof T ? T[P] : undefined) : never;
function getProp<T, P extends keyof T>(obj: T | undefined, prop: P): T[P] | undefined {
    if (typeof obj === "undefined") {
        return undefined;
    }

    return obj[prop];
}

这非常复杂,但它有一些可能理想的行为:

const obj1 = {
    id: 1,
    name: 'obj1',
};
const obj2 = undefined;
const items = [obj1];

getProp(items.find(i => i.id === 1), "id"); // number | undefined
getProp(obj1, "id"); // number
getProp(obj2, "who knows"); // undefined
getProp(Math.random() < 0.5 ? { a: 1 } : { a: "b" }, "a"); // string | number
getProp(Math.random() < 0.5 ? { a: 1 } : { b: 1 }, "z"); // error! "z" not "a" | "b"
getProp(Math.random() < 0.5 ? { a: 1 } : { b: 1 }, "a"); // number | undefined

但是对于您所描述的用例,您只对传入 undefined 感兴趣,因为 obj 可能是 T |对于某些特定的T,undefined,并且您永远不会计划实际调用getProp(undefined, "something")。在这种情况下,您的“天真”方法就足够有效:

function getProp<T, P extends keyof T>(obj: T | undefined, prop: P): T[P] | undefined {
    if (typeof obj === "undefined") {
        return undefined;
    }

    return obj[prop];
}

观察:

getProp(items.find(i => i.id === 1), "id"); // number | undefined
getProp(obj1, "id"); // number | undefined
getProp(obj2, "who knows"); // error!
getProp(Math.random() < 0.5 ? { a: 1 } : { a: "b" }, "a"); // string | number | undefined
getProp(Math.random() < 0.5 ? { a: 1 } : { b: 1 }, "z"); // error! "z" not "a" | "b"
getProp(Math.random() < 0.5 ? { a: 1 } : { b: 1 }, "a"); // number | undefined

可能唯一“糟糕”的事情是 getProp() 的所有输出在其类型中都包含 undefined,即使您正在调用 getProp (obj, "id"),已知定义的 obj 以及已知存在的 "id"。但这似乎就是你想要的,所以就这样吧。你基本上回答了你自己的问题!

所以,呃,希望有帮助。祝你好运!

Link to code

关于typescript - 当 T 未定义时如何输入 `K extends keyof T`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58310991/

相关文章:

angular - ng build --prod 自 Angular CLI 6 以来不缩小/丑化/删除注释

javascript - Sinon - 如何 stub 我想要测试的方法调用的方法

javascript - Typescript中Angular2的Elvis运算符的替换

javascript - 如何获取对象数组对象的 Angular 长度

node.js - Docker Compose:.env:没有这样的文件或目录/NodeJS

javascript - 如何将 Nedb 与 Electron 集成

typescript - Angular 2 服务没有被注入(inject)到组件中

javascript - 无法为 typescript 字典赋值

javascript - TypeScript 中封装的工作原理

javascript - typescript - 字符串字面量类型到类型字符串