[英]How can I restrict a TypeScript method to receive `keyof` values for fields of a certain type?
I am trying to write a function that will update a field of an object if a value that was passed in changed versus what's already in the object. The closest thing i've got so far is我正在尝试编写一个 function,如果传入的值与 object 中已有的值发生变化,它将更新 object 的字段。到目前为止,我最接近的是
type KnownCountryKeys = "defaultCountry" | "country";
type IHasCountry = {
[key in KnownCountryKeys]: Country;
};
export async function maybeUpdateCountry<THasCountry extends IHasCountry>(
dto: THasCountry,
countryKey: KnownCountryKeys,
newCountryCode: string
) {
// Pseudo-Code
// Ideally, typescript could validate at build-time that
// `dto[countryKey]` is in-fact a Country field, from
// the type annotations alone.
if (dto[countryKey].code != newCountryCode) {
const newCountry = //...validateCountry
dto[countryCode] = newCountry;
}
}
My main problem with this approach is that dto
can not have any more fields other than the ones specified in KnownCountryKeys
I get ts2345
, but if I try to convert it to an interface to make the type flexible I get ts2464
.这种方法的主要问题是dto
不能有除KnownCountryKeys
中指定的字段之外的任何其他字段,我得到ts2345
,但是如果我尝试将它转换为接口以使类型灵活,我得到ts2464
。 Furthermore, I'd like to delete KnownCountryKeys
because having that whitelist of field names is a code-smell.此外,我想删除KnownCountryKeys
,因为拥有该字段名称白名单是一种代码味道。
My intent is for this function to receive an arbitrary object of any shape, a string key that is validated by TypeScript to be a field of type Country
, and the key of the new country so I can decided whether the country must be updated in an entirely type-safe fashion.我的目的是让这个 function 接收任意形状的任意 object,一个由 TypeScript 验证为Country
类型字段的字符串键,以及新国家的键,这样我就可以决定是否必须更新国家完全类型安全的时尚。
If I understood You properly, You look for something like:如果我对你的理解正确,你会寻找类似的东西:
type IHasCountry<K extends KnownCountryKeys> = { [key in K]: Country; };
export function maybeUpdateCountry<K extends KnownCountryKeys>(
dto: IHasCountry<K>, countryKey: K, newCountryCode: string) {
// ...
EDIT:编辑:
If you assume that country code is arbitrary string but the DTO should have a field named as country code with type Country, then:如果您假设国家代码是任意字符串,但 DTO 应该有一个名为国家代码且类型为 Country 的字段,那么:
class Country { constructor(readonly name: string) { } };
function maybeUpdateCountry<K extends string, T extends { [key in K]: Country }>(
dto: T, countryKey: K, newCountryCode: string): void {}
const dto1 = { 'pl_PL': new Country('Poland') };
const dto2 = { 'fr_CH': new Country('Switzerland') };
const dto3 = { 'fr_FR': new Country('France') };
maybeUpdateCountry(dto1, 'pl_PL', 'Pologne'); // OK
maybeUpdateCountry(dto2, 'fr_CH', 'Suisse'); // OK
maybeUpdateCountry(dto2, 'fr_FR', 'Suisse');
// ERROR:
// Argument of type '{ fr_CH: Country; }' is not assignable to parameter of type '{ fr_FR: Country; }'.
// Property 'fr_FR' is missing in type '{ fr_CH: Country; }' but required in type '{ fr_FR: Country; }'.
maybeUpdateCountry(dto2, 'test', 'Test');
// ERROR:
// Argument of type '{ fr_CH: Country; }' is not assignable to parameter of type '{ test: Country; }'.
// Property 'test' is missing in type '{ fr_CH: Country; }' but required in type '{ test: Country; }'.
maybeUpdateCountry({ hello: 'bonjour' }, 'test', 'Test');
// ERROR:
// Argument of type '{ hello: string; }' is not assignable to parameter of type '{ test: Country; }'.
// Object literal may only specify known properties, and 'hello' does not exist in type '{ test: Country; }'.
maybeUpdateCountry({ test: 'Not a country' }, 'test', 'Test');
// ERROR:
// Type 'string' is not assignable to type 'Country'
maybeUpdateCountry({ test: new Country('Testland') }, 'test', 'Test'); // OK
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.