从另一个属性引用对象的属性中的键

问题描述 投票:0回答:1

我敢肯定这比我想象的要简单,但我真的什么也没找到。用一个简单的场景更容易解释:

const cookbook: CookBook = {
    ingredients: {
        "tomato": { vegetal: true },
        "cheese": { vegetal: false },
        "lettuce": { vegetal: true },
    },

    recipes: {
        "pizza": ["tomato", "cheese"],
        "salad": ["tomato", "lettuce"]
    }
}

type CookBook = {
    ingredients: {[key: string]: {vegetal: boolean}},
    recipes: {[key: string]: string[]}
}

可以看到在recipes属性中,values表示的是成分列表,也就是单纯的字符串。我如何指示这些字符串应该是配料对象的键?

    ...
    recipes: {
        // This should not be valid because "pineapple" 
        // is not a key in ingredients property.
        "pizza": ["tomato", "cheese", "pineapple"],
        ...
    }
}
typescript
1个回答
0
投票

你可以写一个带有泛型参数的函数

const cookbook = createCookBook({
    ingredients: {
        "tomato": { vegetal: true },
        "cheese": { vegetal: false },
        "lettuce": { vegetal: true },
    },

    recipes: {
        "pizza": ["tomato", "cheese"],
        "salad": ["tomato", "lettuce"]
    }
})
const createCookBook =
    <T extends CookBook & IsValidCookBook<T>>
        (cookbook: Narrow<T>) => cookbook

type IsValidCookBook<T extends CookBook> = {
    ingredients: T['ingredients'],
    recipes: { [K in keyof T['recipes']]: (keyof T['ingredients'])[] }
}

type Narrow<T> = {
  [K in keyof T]
    : K extends keyof [] ? T[K]
    : T[K] extends (...args: any[]) => unknown ? T[K]
    : Narrow<T[K]>
};

游乐场

我们正在根据推断的

ValidCookBook
对象构建一个有效的
Cookbook
对象并比较两者。这可以在 IDE 中提供良好的开发人员体验。

Narrow
用于防止 TS 扩大食谱中的成分数组,尽管现在可能有更清洁的方法来做到这一点。

© www.soinside.com 2019 - 2024. All rights reserved.