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

huangapple go评论55阅读模式
英文:

Referencing an object's keys in a property from another property

问题

我确定这比我想的简单,但我真的没有找到任何方法。用一个简单的场景来解释会更容易:

您可以看到在食谱属性中,值表示的是一些简单的字符串配料。我该如何指示这些字符串应该是配料对象的一个键呢?

// 这应该是无效的,因为“pineapple”不是配料属性中的键。
"pizza": ["tomato", "cheese", "pineapple"],
英文:

I'm sure this is simpler than I think but I really haven't found anything. It's easier to explain with a simple scenario:

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[]}
}

You can see that in the recipes property, the values ​​represent lists of ingredients, which are mere strings. How could I indicate that those strings should be a key of the ingredients object?

    ...
    recipes: {
        // This should not be valid because "pineapple" 
        // is not a key in ingredients property.
        "pizza": ["tomato", "cheese", "pineapple"],
        ...
    }
}

答案1

得分: 2

您可以编写一个带有通用参数的函数。

我们正在根据推断的“Cookbook”对象构建一个有效的“ValidCookBook”对象并进行比较。这在IDE中提供了良好的开发人员体验

Narrow”用于防止TS扩展配方中的食材数组,尽管现在可能有更干净的方法来做这件事。

---

类型级别的替代方法如下:

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

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

{type Test = ValidateCookBook<typeof cookbook>;}
type ValidateCookBook <T extends CookBook & IsValidCookBook<T>> = never;

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

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

You can write a function with a generic parameter

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

    recipes: {
        &quot;pizza&quot;: [&quot;tomato&quot;, &quot;cheese&quot;],
        &quot;salad&quot;: [&quot;tomato&quot;, &quot;lettuce&quot;]
    }
})
const createCookBook =
    &lt;T extends CookBook &amp; IsValidCookBook&lt;T&gt;&gt;
        (cookbook: Narrow&lt;T&gt;) =&gt; cookbook

type IsValidCookBook&lt;T extends CookBook&gt; = {
    ingredients: T[&#39;ingredients&#39;],
    recipes: { [K in keyof T[&#39;recipes&#39;]]: (keyof T[&#39;ingredients&#39;])[] }
}

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

playground

We are constructing a valid ValidCookBook object based of the inferred Cookbook object and comparing the two. This enables a good developer experience in the IDE.

Narrow is used to prevent TS from widening the ingredients array in the recipes, although there are probably cleaner ways to do it now.


The type-level alternative looks like this

const cookbook = {
    ingredients: {
        &quot;tomato&quot;: { vegetal: true },
        &quot;cheese&quot;: { vegetal: false },
        &quot;lettuce&quot;: { vegetal: true },
    },

    recipes: {
        &quot;pizza&quot;: [&quot;tomato&quot;, &quot;cheese&quot;],
        &quot;salad&quot;: [&quot;tomato&quot;, &quot;lettuce&quot;]
    }
} as const;

{type Test = ValidateCookBook&lt;typeof cookbook&gt;}
type ValidateCookBook &lt;T extends CookBook &amp; IsValidCookBook&lt;T&gt;&gt; = never;

type IsValidCookBook&lt;T extends CookBook&gt; = {
    ingredients: T[&#39;ingredients&#39;],
    recipes: { [K in keyof T[&#39;recipes&#39;]]: readonly (keyof T[&#39;ingredients&#39;])[] }
}

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

playground

huangapple
  • 本文由 发表于 2023年2月27日 01:03:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75573615.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定