在TypeScript中,您应该声明数据的类型。

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

What type should I declare for my data (using TypeScript)?

问题

您可以使用 TypeScript 中的映射类型来声明结果类型并实现您的需求。以下是一个示例:

type ResultType = {
    [K in SecondEnum]: {
        [P in FirstEnum]?: string;
    };
};

const getSecondEnumValuesBasedOnMap: ResultType = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    },
    [SecondEnum.secondEnumKey2]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
    [SecondEnum.secondEnumKey3]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
};

这个 ResultType 类型将确保您的 getSecondEnumValuesBasedOnMap 符合指定的结构。如果您更改了映射或结果不符合所需的结构,TypeScript 将会发出相应的错误提示,帮助您保持类型一致性。

英文:

This is part of my TypeScript code.

enum FirstEnum {
    firstEnumKey1 = 'firstEnumKey1',
    firstEnumKey2 = 'firstEnumKey2',
    firstEnumKey3 = 'firstEnumKey3',
    firstEnumKey4 = 'firstEnumKey4',
}

enum SecondEnum {
    secondEnumKey1 = 'secondEnumKey1',
    secondEnumKey2 = 'secondEnumKey2',
    secondEnumKey3 = 'secondEnumKey3',
}

// map first enum to second enum
const map: {[i in FirstEnum]: SecondEnum[] } = {
    'firstEnumKey1': [SecondEnum.secondEnumKey1],
    'firstEnumKey2': [],
    'firstEnumKey3': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
    'firstEnumKey4': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
};

I have two enums and a const which map them. I'm using the map to define some data that for each SecondEnum has an object. The object keys should be map keys which had that specific SecondEnum value in their array.
So now my result should be like this.

const getSecondEnumValuesBasedOnMap = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    },
    [SecondEnum.secondEnumKey2]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
    [SecondEnum.secondEnumKey3]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
}

If I change my map my data should change based on it. for example if I add SecondEnum.secondEnumKey2 to FirstEnum.firstEnumKey2 my data should change like this:

// map first enum to second enum
const map: {[i in FirstEnum]: SecondEnum[] } = {
    'firstEnumKey1': [SecondEnum.secondEnumKey1],
    'firstEnumKey2': [SecondEnum.secondEnumKey2],
    'firstEnumKey3': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
    'firstEnumKey4': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
};

const getSecondEnumValuesBasedOnMap = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    },
    [SecondEnum.secondEnumKey2]: {
        [FirstEnum.firstEnumKey2]: 'some value',
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
    [SecondEnum.secondEnumKey3]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
}

I want to declare a type for my result so when I changed my map I get errors to update my result but I'm kind of new to typescript and I don't know how.

答案1

得分: 3

以下是您要翻译的内容:

首先,我们需要更改 map 的类型,因为它当前没有为 SecondEnum 提供文字值,我们无法确定使用了哪些确切的值。

为了防止编译器扩展类型,我们将使用 const assertion,并且为了保持类型安全性,我们将使用 satisfies 运算符:

const map = {
  firstEnumKey1: [SecondEnum.secondEnumKey1],
  firstEnumKey2: [SecondEnum.secondEnumKey2],
  firstEnumKey3: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
  firstEnumKey4: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const satisfies {[K in FirstEnum]: readonly SecondEnum[]};

// 类型 EnumMap = {
//   readonly firstEnumKey1: readonly [SecondEnum.secondEnumKey1];
//   readonly firstEnumKey2: readonly [SecondEnum.secondEnumKey2];
//   readonly firstEnumKey3: readonly [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3];
//   readonly firstEnumKey4: readonly [...];
// }
type EnumMap = typeof map;

接下来,让我们定义一个类型,它接受一个由 SecondEnum 约束的泛型参数,并查找在 map 中具有此特定项的 FirstEnum 成员。我们将使用 mapped types 遍历 map,并使用 key remapping 来排除不适合的成员,并最终返回具有此第二枚举值的 map 键:

type FindValue<T extends SecondEnum> = keyof  {
  [K in keyof EnumMap as T extends  EnumMap[K][number] ? K : never]:EnumMap[K]
}

让我们为 getSecondEnumValuesBasedOnMap 定义一个类型。我们将再次使用 mapped typeskey remapping 来排除根本未使用的第二枚举成员:

{
  [K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
    [P in FindValue<K>]: string
  }
}

请注意,在 [FindValue<K>] extends [never] 中的 [] 非常重要,因为 never 是一个空集,并且是每个联合类型的超类型,为了确保此检查按预期工作,我们使用 [] 防止编译器分发类型。

在值中,我们正在遍历 FindValue<K> 的结果,该结果返回了第二个枚举用于的键,并分配了类型 string 的值:

const getSecondEnumValuesBasedOnMap:{
  [K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
    [P in FindValue<K>]: string
  }
} = {
  [SecondEnum.secondEnumKey1]: {
    [FirstEnum.firstEnumKey1]: 'some value',
  },
  [SecondEnum.secondEnumKey2]: {
    [FirstEnum.firstEnumKey2]: 'some value',
    [FirstEnum.firstEnumKey3]: 'some value',
    [FirstEnum.firstEnumKey4]: 'some value',
  },
  [SecondEnum.secondEnumKey3]: {
    [FirstEnum.firstEnumKey3]: 'some value',
    [FirstEnum.firstEnumKey4]: 'some value',
  },
};

playground

英文:

First of all, we need to change the type of the map, since it is currently not having literal values for the SecondEnum and we won't be able to determine which exact values are used.

To prevent the compiler from widening the types we will use const assertion and to maintain type safety we will use satisfies operator:

const map = {
  firstEnumKey1: [SecondEnum.secondEnumKey1],
  firstEnumKey2: [SecondEnum.secondEnumKey2],
  firstEnumKey3: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
  firstEnumKey4: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const satisfies {[K in FirstEnum]: readonly SecondEnum[]};

// type EnumMap = {
//   readonly firstEnumKey1: readonly [SecondEnum.secondEnumKey1];
//   readonly firstEnumKey2: readonly [SecondEnum.secondEnumKey2];
//   readonly firstEnumKey3: readonly [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3];
//   readonly firstEnumKey4: readonly [...];
// }
type EnumMap = typeof map;

Next, let's define a type that accepts a generic parameter constrained by SecondEnum and find the members of FirstEnum that have this specific item in the map. We are going to use mapped types to map through the map and key remapping to exclude those that are not suitable, and at the end return the keys of the map that have this second enum in them:

type FindValue<T extends SecondEnum> = keyof  {
  [K in keyof EnumMap as T extends  EnumMap[K][number] ? K : never]:EnumMap[K]
}

Let's define a type for the getSecondEnumValuesBasedOnMap. We will need to use mapped types and key remapping again to exclude those second enum members that are not used at all:

{
  [K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
    [P in FindValue<K>]: string
  }
}

Note that [] are really important in the [FindValue<K>] extends [never], since never is an empty set and is a supertype for every union and to make sure that this check works as expected we prevent the compiler from distributing the types using the [].
And in the values, we are mapping through the result of FindValue<K> which returns as the keys where the second enum is used and assigns a value of type string:

const getSecondEnumValuesBasedOnMap:{
  [K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
    [P in FindValue<K>]: string
  }
} = {
  [SecondEnum.secondEnumKey1]: {
    [FirstEnum.firstEnumKey1]: 'some value',
  },
  [SecondEnum.secondEnumKey2]: {
    [FirstEnum.firstEnumKey2]: 'some value',
    [FirstEnum.firstEnumKey3]: 'some value',
    [FirstEnum.firstEnumKey4]: 'some value',
  },
  [SecondEnum.secondEnumKey3]: {
    [FirstEnum.firstEnumKey3]: 'some value',
    [FirstEnum.firstEnumKey4]: 'some value',
  },
};

playground

答案2

得分: 0

以下是您要翻译的内容:

声明类型如下:

type GetSecondEnumValuesBasedOnMap = {
    [K in SecondEnum]: Partial<{ [L in FirstEnum]: string }>
}

然后使用如下:

const getSecondEnumValuesBasedOnMap: GetSecondEnumValuesBasedOnMap = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    }
}
英文:

declare type like this:

type GetSecondEnumValuesBasedOnMap = {
[K in SecondEnum]: Partial&lt;{ [L in FirstEnum]: string }&gt;

}

then use like this:

const getSecondEnumValuesBasedOnMap: GetSecondEnumValuesBasedOnMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: &#39;some value&#39;,
}

答案3

得分: 0

我认为最好将地图声明为一种类型,而不是一个常数(假设您在计算中没有使用它)。如果您这样做,还可以反转键和值以使映射更容易,您可以像这样声明所有类型:

Playground链接

type EnumTypeMap = {
  [SecondEnum.secondEnumKey1]: FirstEnum.firstEnumKey1;
  [SecondEnum.secondEnumKey2]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
  [SecondEnum.secondEnumKey3]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
};

type ValueEnumTypeMap = {
  [key in keyof EnumTypeMap]: {
    // Unfortunately I wasn&#39;t sure how else to set the type of the index as `EnumTypeMap[key]`
    // (loops through a single key and then changes the type to the type we need)
    [innerKey in keyof { key: key } as EnumTypeMap[key]]: string;
  };
};

const getSecondEnumValuesBasedOnMap: ValueEnumTypeMap = {
  [SecondEnum.secondEnumKey1]: {
    [FirstEnum.firstEnumKey1]: "some value",
  },
  [SecondEnum.secondEnumKey2]: {
    [FirstEnum.firstEnumKey2]: "some value", // Error
    [FirstEnum.firstEnumKey3]: "some value",
    [FirstEnum.firstEnumKey4]: "some value",
  },
  [SecondEnum.secondEnumKey3]: {
    [FirstEnum.firstEnumKey3]: "some value",
    [FirstEnum.firstEnumKey4]: "some value",
  },
};
英文:

I think it would be better to declare the map as a type rather than a constant (assuming you do not also need to use it in your calculations).<br/> If you do that and also invert the keys and values to make the mapping easier, you can declare all the types like this:

Playground Link

type EnumTypeMap = {
  [SecondEnum.secondEnumKey1]: FirstEnum.firstEnumKey1;
  [SecondEnum.secondEnumKey2]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
  [SecondEnum.secondEnumKey3]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
};

type ValueEnumTypeMap = {
  [key in keyof EnumTypeMap]: {
    // Unfortunately I wasn&#39;t sure how else to set the type of the index as `EnumTypeMap[key]`
    // (loops through a single key and then changes the type to the type we need)
    [innerKey in keyof { key: key } as EnumTypeMap[key]]: string;
  };
};

const getSecondEnumValuesBasedOnMap: ValueEnumTypeMap = {
  [SecondEnum.secondEnumKey1]: {
    [FirstEnum.firstEnumKey1]: &quot;some value&quot;,
  },
  [SecondEnum.secondEnumKey2]: {
    [FirstEnum.firstEnumKey2]: &quot;some value&quot;, // Error
    [FirstEnum.firstEnumKey3]: &quot;some value&quot;,
    [FirstEnum.firstEnumKey4]: &quot;some value&quot;,
  },
  [SecondEnum.secondEnumKey3]: {
    [FirstEnum.firstEnumKey3]: &quot;some value&quot;,
    [FirstEnum.firstEnumKey4]: &quot;some value&quot;,
  },
};

huangapple
  • 本文由 发表于 2023年6月26日 15:40:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76554522.html
匿名

发表评论

匿名网友

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

确定