Flowtype / Typescript通用获取属性

时间:2016-08-12 21:26:20

标签: javascript typescript types flowtype

有没有办法在flow或typescript中正确键入检查以下代码?:

type A = {
    x: string
}
type B = {
    y: string
}
function get(obj, prop) {
    return obj[prop];
}
const a: A = { x: 'x' }
const b: B = { y: 'y' }

get(a, 'x') // should type check
get(b, 'y') // should type check
get(a, 'y') // should NOT type check
get(b, 'x') // should NOT type check

其中get是任何类型的obj的通用函数。我们是否可以通过流检查obj prop是否有if (a && a.b && a.b.c && a.b.c.d === 'blah') { ... } 的方式对代码进行注释?

主要用例是为深层属性编写通用get函数。具有与_.get类似功能的东西。我试图避免这种情况:

$Keys

编辑:

如@vkurchatkin所述,我们可以使用get<T: {}>(obj: T, prop1: $Keys<T>, prop2: /* ! */): /* ! */ { ... } 。但我只能使用1级深度的getter函数。我们如何键入以下函数:

type A = {
    x: B
}

type B = {
    y: string
}

type GetDeep<T: {}, U, V> = Helper<T, U, V, Get<T, U>, Get<U, V>>

type Helper<T, U, V,   W, X> = (obj: T, a: $Keys<T>, b: $Keys<U>) => V

type Get<T, U> = (obj: T, a: $Keys<T>) => U;

// NOTE: here if I replace GetDeep<*, B, *> with GetDeep<*, *, *>
//       then it wrongly type checks everything
const getDeep: GetDeep<*, B, *> = (obj, a, b) => {
    return obj[a][b];
}

var va: A = {
    x: {y: 'abc'}
}

getDeep(va, 'x', 'y'); // ok
getDeep(va, 'x', 'z'); // error

编辑2:

到目前为止,我写了以下内容:

type Get<T, U> = (obj: T, a: $Keys<T>) => U

U中看来,obj[a]不是{{1}}值的类型。

2 个答案:

答案 0 :(得分:5)

你可以使用Flow:

function get<T: {}>(obj: T, prop: $Keys<T>) {
    return obj[prop];
}

不幸的是,返回的类型被推断为any。 Flow目前正在进行$PropertyType,所以我相信这将来有可能(它还没有按预期工作):

function get<T: {}, P: $Keys<T>>(obj: T, prop: P): $PropertyType<T, P> {
    return obj[prop];
}

使用此类型,您可以深入两个级别:

function getDeep<
    T: {},
    P: $Keys<T>,
    R: $PropertyType<T, P>,
    P2: $Keys<R>
  >(obj: T, a: P, b: P2): $PropertyType<R, P2> {
    return obj[a][b];
}

或制作可组合的东西。

答案 1 :(得分:0)

  

其中get是任何类型的obj的通用函数。我们能否以流将检查obj是否具有prop

的方式来注释代码

使用TypeScript无法做到这一点。

  

具有与_.get

类似功能的东西

如果安全导航操作员可用,则会更容易:https://github.com/Microsoft/TypeScript/issues/16

然而,JavaScript委员会需要坚持下去,据我所知,它很遗憾没有被任何人所支持。

直到那时我还完成了a && a.b等等。

更多

我清理其他人代码时有时会使用的慢功能:

export function safe<T>(action: () => T): T | undefined {
    try {
        return action();
    }
    catch (ex) {
        return undefined;
    }
}

// Usage
let c = safe(()=>a.b.c);