打字打字能确保函数返回要求的键吗?

时间:2019-03-13 14:32:48

标签: typescript

某些Web服务根据请求的属性提供东西。我想创建一个带有属性的函数,在内部调用Web服务并返回请求的数据。

使用数据的函数现在应该知道特定的键现在不是未定义的。

当我自己寻找解决方案时,我发现了一些可能有用的东西,但无法从中创建有用的东西:

还有一个额外的麻烦:在这种情况下,总是有默认属性,例如id。

    interface Something {
        id: string;
        foo?: string;
        bar?: number;
    }

    // use 'keyof Something' in some ways here?
    type OptionalProp = 'foo' | 'bar'

    type SomethingSpecific<K extends keyof Something> = {
        [k in K]: NonNullable<Something[k]>
    };

    function get(properties: OptionalProp[]): Something {
        const result: Something = {
            id: '1337'
        };

        if (properties.includes('foo')) {
            result.foo = 'bar';
        }

        if (properties.includes('bar')) {
            result.bar = 42;
        }

        return result;
    }

    console.log(usage());
    function usage(): number {
        const result = get(['bar']);
        return result.bar * 1;
    }

1 个答案:

答案 0 :(得分:1)

因此,可以使用Can I Use来确定类型的哪些键是可选的,并且您还可以为get()函数提供一个调用签名,该函数承诺返回一个带有某些内容的Something现在需要使用以前可选的属性(最好将其设为一个a way的函数,以使实现签名可以像以前一样松散;否则,在实现中会引起很多抱怨) 。还要注意,标准库中有一个名为overload的类型别名,该别名采用对象类型T并返回新类型,其中现在需要所有可选属性。将Required<T>Pick<T, K>Required<T>结合使用应该可以:

interface Something {
  id: string;
  foo?: string;
  bar?: number;
}

// get the optional keys of an object type
type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T];

type OptionalProp = OptionalKeys<Something>

// make get() a generic function that returns an intersection of Something with
//  a Required<Pick<Something, K>> for the passed-in K parameters

function get<K extends OptionalProp>(
  properties: K[]
): Required<Pick<Something, K>> & Something;
function get(properties: OptionalProp[]): Something {
  // impl here
  return null!
}

const result = get(['bar']);
// const result: Required<Pick<Something, "bar">> & Something
result.bar * 1; // okay now

这应该为您工作。请注意,返回的get()类型将是像Required<Pick<Something, "bar">> & Something这样的交集类型。如果您想要一种更直接的属性包对象类型,则可以将get()签名更改为对实现者来说较难看但对调用者来说更好:

function get<K extends OptionalProp,
  R extends Something=Required<Pick<Something, K>> & Something
>(properties: K[]): { [P in keyof R]: R[P] };
function get(properties: OptionalProp[]): Something { /* impl */ }
  // impl here
  return null!
}

const result = get(['bar']);
//const result: {
//    bar: number;
//    id: string;
//    foo?: string | undefined;
//}

好的,希望能有所帮助。祝你好运!