首页 > 解决方案 > 打字稿打字可以确保函数返回请求的键吗?

问题描述

一些 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;
    }

标签: typescript

解决方案


因此,有一种方法可以确定类型的哪些键是可选的,您还可以为该函数提供调用签名,该get()函数承诺返回 aSomething以及现在需要的一些以前可选的属性(最好是它是一个重载的函数,以便实现签名可以像以前一样保持松散;否则你会在实现中收到很多抱怨)。另请注意,Required<T>在标准库中调用了一个类型别名,它采用对象类型T并返回一个新类型,现在需要所有可选属性。使用Required<T>andPick<T, K>组合应该可以工作:

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;
//}

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


推荐阅读