只定义对象的键和自动生成值的类型

问题描述

我正在尝试做类似的事情:

type Sizes = 'small' | 'large';

const CONfig_BY_SIZE: Record<Sizes,any> = {
    small: {
        a: ...,b: ...,c: ...,},large: {
        a: ...,}

它有效,但是当我尝试输入 CONfig_BY_SIZE.large. 时,abc 没有自动完成。我认为这是因为我将值定义为任何。 值本身很大,所以如果可能的话,我更喜欢它自动生成

我的目标是将键定义为 Sizes 但我仍然可以自动完成该值。 我如何实现这一目标?

谢谢!

解决方法

如果您想应用某种类型约束,但从值中推断出比该约束更具体的内容,那么这就是函数的泛型参数所做的。

所以我认为您需要提供一个函数来允许打字稿进行推断:

function createConfigBySize<T extends Record<Sizes,unknown>>(config: T): T {
  return config
}

这样做是将 T 映射到 extends Record<Sizes,unknown>。 Typescript 准确记录了它是什么子类型,并将其保存到 T。然后将返回类型设置为 T 以获取推断的任何内容。

现在你可以这样做:

const CONFIG_BY_SIZE = createConfigBySize({
    small: {
        a: 123,b: 'abc',c: false,},large: {
        a: { cool: true },b: null,c: [1,2,3],})

产生这种类型的:

{
    small: {
        a: number;
        b: string;
        c: boolean;
    };
    large: {
        a: {
            cool: boolean;
        };
        b: null;
        c: number[];
    };
}

如果您使用无效的大小键,您仍然可以进行类型检查:

createConfigBySize({
  small: { foo: 123 },medium: { bar: 123 },// type error
})

Working playground


也就是说,如果您希望 small.alarge.a 的类型相同,这不是正确的解决方案。在这种情况下,您确实应该为任何类型创建一个接口。如果您需要在多个地方重用一个类型,那么正式声明该接口是一个非常好的主意。

,

您可以使用类似的语法来强制对象具有联合类型中每个条目的键:

type Sizes = 'small' | 'large';
type Keys = 'a' | 'b' | 'c';

const CONFIG_BY_SIZE: Record<Sizes,{ [key in Keys]: any }> = {
    small: {
        a: 1,b: 2,c: 2,large: {
        a: 2,}

enter image description here

您也可以将其设为泛型。

代码示例 here