TypeScript函数:从其参数中省略某些键并添加其他键

4
我正在编写一个函数,其职责是将原始的API响应转换为更易于在我的应用程序中使用的形状(让我们称之为“漂亮”的响应)。
根据TS编译器,下面的代码是有效的,但我希望它抱怨我在返回之前没有从原始响应中删除“metadata”键,因为“metadata”存在于“RawResponse”中,但不存在于“PrettyResponse”中。
我认为我的“Optionalize”类型会为我做这件事,但似乎没有起作用。
我在这里误解了什么?

以下是TS Playground链接 以作说明。

// Omit from T the keys in common with K
type Optionalize<T extends K, K> = Omit<T, keyof K>;

interface RawResponse {
    data: [];
    metadata: Object;
}

type PrettyResponse<T extends RawResponse> = Optionalize<T, RawResponse> & {
    data: [];
    version: string;
};

/**
 * Take a raw api response and transform it into a pretty one.
 * All raw responses have at least the keys of RawResponse. 
 */
function parseResponse<T extends RawResponse>(response: T): PrettyResponse<T> {
    const result = Object.assign({}, response, {
        version: '123'
    });
    // Shouldn't I have to delete result.metadata before returning?
    return result;
}

以下是使用它的示例:

interface MyResponse {
    data: [];
    name: string;
    category: string;
    other?: number;
    metadata: Object;
}

const response: MyResponse = {
    data: [],
    name: 'a',
    category: 'blah',
    metadata: {}
}

const myPrettyResponse: PrettyResponse<MyResponse> = parseResponse<MyResponse>(response);

注意:我的同事指出这可能是由于Typescript使用结构子类型,但我仍然期望Optionalize<T, RawResponse>的显式返回定义可以移除metadata键。

1个回答

3

我认为你需要在MyResponse中添加metadata: never,这样它就会不断地提示你将其删除(设置为未定义)。

interface RawResponse {
    data: [];
    metadata: Object;
}

type BannedKeys = 'metadata';

type PrettyResponse<T> = Omit<T, BannedKeys> & Record<BannedKeys, never> & {
    version: string;
}

function parseResponse<T extends RawResponse>(response: T): PrettyResponse<T> {
    const updatedResponse: PrettyResponse<T> = {
        ...response,
        version: '123',
        metadata: undefined, // if you comment it - it will ask to delete it.
    }

    return updatedResponse;
}

interface MyResponse {
    data: [];
    name: string;
    category: string;
    other?: number;
    metadata: Object;
}

const response: MyResponse = {
    data: [],
    name: 'a',
    category: 'blah',
    metadata: {}
}

const myPrettyResponse: PrettyResponse<MyResponse> = parseResponse<MyResponse>(response);

myPrettyResponse.metadata // is undefined.

虽然这样做可以工作,但它不具有可扩展性,因为它要求调用者跟上他们不关心的RawResponse中多余属性的最新信息。 - jamis0n
你想从 RawResponse 中获取所有属性并仅排除被禁止的属性吗?这样正确吗? - satanTime
你能给我一个选项吗?从问题中听起来,你想禁止实现在上面的“元数据”。 - satanTime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接