通过Typescript对象:接口,但继续输入

发布于 2025-01-31 14:56:21 字数 1056 浏览 2 评论 0原文

我有一种方法,该方法采用了一个对象,这是我喜欢用对象的对象进行迭代的部分,然后基于我喜欢执行某些操作的密钥。接口的键是字符串,但值是字符串| number | string [] | dateTime。我希望我通过它的功能来知道从密钥中传递的内容。

我当前拥有的代码是

public partialUpdate = async (id: number, fieldsToUpdate: Partial<IClient>) => {

    type temp = Partial<Record<keyof IClient, (val : string) => void>>;
    const mapping : temp = {
        name: (val) => client.setName(val),
        website: (val) => client.setWebsite(val),
        sic_codes: (val) => client.setSicCodes(val),
        phone_number: (val) => client.setPhoneNumber(val),
    };
    Object.entries(fieldsToUpdate).forEach(([key, value]) => mapping[key](value));
    return this.clientRepository.update(id, client);
};

,接口是

export interface IClient
{
    id: number,
    creation_date: DateTime,
    name:string,
    website:string,
    phone_number:string,
    industry:string,
    sic_codes:string[],
}

我当前遇到的问题是,如果是字符串类型,那么没有问题,但是由于sic_codes是字符串[],它将导致类型错误。有什么方法可以让const映射知道键是哪种类型的val?

I have a method which takes an object which is a Partial I wuold like to itterate though that object using Object.entries and then based on the key I wuold like to perform some operations. The interface has keys which are string but values which are string|number|string[]|DateTime. I would like the function I pass it to to know whats being passed in from the key.

The code i currently have is

public partialUpdate = async (id: number, fieldsToUpdate: Partial<IClient>) => {

    type temp = Partial<Record<keyof IClient, (val : string) => void>>;
    const mapping : temp = {
        name: (val) => client.setName(val),
        website: (val) => client.setWebsite(val),
        sic_codes: (val) => client.setSicCodes(val),
        phone_number: (val) => client.setPhoneNumber(val),
    };
    Object.entries(fieldsToUpdate).forEach(([key, value]) => mapping[key](value));
    return this.clientRepository.update(id, client);
};

and the interface is

export interface IClient
{
    id: number,
    creation_date: DateTime,
    name:string,
    website:string,
    phone_number:string,
    industry:string,
    sic_codes:string[],
}

The problem i'm currently having is if it were all string types then no issue but because of sic_codes being a string[] it will cause a type error. Is there any way to have const mapping to know what type val is from the key?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

轻许诺言 2025-02-07 14:56:24

您的原始类型

Record<keyof IClient, (val: string) => void>

使用代码>实用程序类型,以a 。让我们用映射类型明确地写出来:

{[K in keyof IClient]: (val: string) => void}

因此,这里的问题是val type 字符串不一定是iclient 在ICLIENT的每个键k中。修复程序是用string iclient [k]索引访问类型,其意思是“ iclient的值类型在键k”:

type Test = { [K in keyof IClient]: (val: IClient[K]) => void };
/* type Test = {
  id: (val: number) => void;
  creation_date: (val: Date) => void;
  name: (val: string) => void;
  company_number: (val: string) => void;
  website: (val: string) => void;
  phone_number: (val: string) => void;
  industry: (val: string) => void;
  sic_codes: (val: string[]) => void;
} */

看起来不错。


如果我们将其插入您的原始类型的位置,则仍然存在错误。 object.entries()不足以在打字稿中使用您想要的内容。请参阅此问题有关更多信息。您可以给它更强大的键入(即使这不是100%安全的)。即使这样做,您的foreach()回调也必须为 generic 在特定的密钥类型中k您正在处理。在该回调中,您需要确保您的value和您的映射[键]不是undefined,如果您想安全:

让我进行这些更改,只是表明它按照您的意图起作用:

// Give stronger typings to Object.entries()
type Entry<T extends object> = { [K in keyof T]-?: [K, T[K]] }[keyof T];
function entries<T extends object>(obj: T) {
    return Object.entries(obj) as Entry<T>[];
}

const partialUpdate = async (id: number, fieldsToUpdate: Partial<IClient>) => {
    const client = new Client();    
    const mapping: Partial<{ [K in keyof IClient]: (val: IClient[K]) => void }> = {
        name: (val) => client.setName(val),
        company_number: (val) => client.setCompanyNumber(val),
        industry: (val) => client.setIndustry(val),
        sic_codes: (val) => client.setSicCodes(val),
    };
    const e = entries(fieldsToUpdate).forEach(<K extends keyof IClient>(
        [key, value]: [K, IClient[K] | undefined]) => value && mapping[key]?.(value));
    return null;
};

哇,没有错误!

Playground link to code

Your original type

Record<keyof IClient, (val: string) => void>

uses the Record<K, V> utility type, which is implemented as a mapped type. Let's write that out explicitly in terms of mapped types:

{[K in keyof IClient]: (val: string) => void}

So, the issue here is that the val type string is not necessarily the value type of IClient at each key K in keyof IClient. And the fix is to replace string with IClient[K], an indexed access type which means "the value type of IClient at key K":

type Test = { [K in keyof IClient]: (val: IClient[K]) => void };
/* type Test = {
  id: (val: number) => void;
  creation_date: (val: Date) => void;
  name: (val: string) => void;
  company_number: (val: string) => void;
  website: (val: string) => void;
  phone_number: (val: string) => void;
  industry: (val: string) => void;
  sic_codes: (val: string[]) => void;
} */

Looks good.


If we plug that in where you had your original type, there are still errors. Object.entries() isn't strongly typed enough to work for what you want in TypeScript. See this SO question for more information. You can give it stronger typings (even though this isn't 100% safe). Even if you do that, your forEach() callback needs to be generic in the particular key type K you're processing. And inside that callback you need to make sure both your value and your mapping[key] are not undefined, if you want to be safe:

Let me make those changes, just to show that it works as you intend:

// Give stronger typings to Object.entries()
type Entry<T extends object> = { [K in keyof T]-?: [K, T[K]] }[keyof T];
function entries<T extends object>(obj: T) {
    return Object.entries(obj) as Entry<T>[];
}

const partialUpdate = async (id: number, fieldsToUpdate: Partial<IClient>) => {
    const client = new Client();    
    const mapping: Partial<{ [K in keyof IClient]: (val: IClient[K]) => void }> = {
        name: (val) => client.setName(val),
        company_number: (val) => client.setCompanyNumber(val),
        industry: (val) => client.setIndustry(val),
        sic_codes: (val) => client.setSicCodes(val),
    };
    const e = entries(fieldsToUpdate).forEach(<K extends keyof IClient>(
        [key, value]: [K, IClient[K] | undefined]) => value && mapping[key]?.(value));
    return null;
};

Hooray, no errors!

Playground link to code

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文