gpt4 book ai didi

typescript 将未知类型转换为接口(interface)类型

转载 作者:行者123 更新时间:2023-12-04 11:59:25 49 4
gpt4 key购买 nike

我想写一个函数 asA接受类型为 unknown 的参数并将其作为特定接口(interface)类型返回 A , 或者如果参数与接口(interface)类型不匹配则抛出错误 A .

该解决方案应该是稳健的。 IE。如果在我的界面类型中添加一个新字段 A ,编译器应该提示我的函数缺少对新字段的检查,直到我修复它。

下面是这样一个函数的例子 asA ,但它不起作用。编译器说:

Element implicitly has an 'any' type because expression of type '"a"' can't be used to index type '{}'. Property 'a' does not exist on type '{}'.(7053)


interface A {
a: string
}

function asA(data:unknown): A {
if (typeof data === 'object' && data !== null) {
if ('a' in data && typeof data['a'] === 'string') {
return data;
}
}
throw new Error('data is not an A');

}

let data:unknown = JSON.parse('{"a": "yes"}');
let a = asA(data);

如何编写函数 asA如上所述?

我可以使用类型转换,例如 (data as any)['a'] ,只要在向 A 添加新字段时没有静默失败.

最佳答案

您可以使用现有的解决方案,例如 typescript-is ,尽管这可能需要您切换到 ttypescript (允许插件的编译器的自定义构建)

如果您需要自定义解决方案,我们可以在普通 TS 中构建一个。首先要求:

  • 验证属性是否属于特定类型
  • 确保验证新字段。

  • 最后一个要求可以通过具有与 A 相同的键的对象来满足。 , 需要所有键,值是属性的类型。这种对象的类型是 Record<keyof A, Types> .然后可以将此对象用作验证的源,我们可以获取每个键并验证它的指定类型:
    interface A {
    a: string
    }

    type Types = "string" | "number" | "boolean";
    function asA(data: unknown): A {
    const keyValidators: Record<keyof A, Types> = {
    a: "string"
    }
    if (typeof data === 'object' && data !== null) {
    let maybeA = data as A
    for (const key of Object.keys(keyValidators) as Array<keyof A>) {
    if (typeof maybeA[key] !== keyValidators[key]) {
    throw new Error('data is not an A');
    }
    }
    return maybeA;
    }
    throw new Error('data is not an A');

    }

    let data: unknown = JSON.parse('{"a": "yes"}');
    let a = asA(data);

    Play

    我们可以更进一步,创建一个可以验证任何对象类型的通用工厂函数,我们还可以允许一些额外的事情,比如指定一个函数,或允许可选属性:
    interface A {
    a: string
    opt?: string
    // b: number // error if you add b
    }

    function asOptional<T>(as: (s: unknown, errMsg?: string) => T) {
    return function (s: unknown, errMsg?: string): T | undefined {
    if (s === undefined) return s;
    return as(s);
    }
    }

    function asString(s: unknown, errMsg: string = ""): string {
    if (typeof s === "string") return s as string
    throw new Error(`${errMsg} '${s} is not a string`)
    }

    function asNumber(s: unknown, errMsg?: string): number {
    if (typeof s === "number") return s as number;
    throw new Error(`${errMsg} '${s} is not a string`)
    }

    type KeyValidators<T> = {
    [P in keyof T]-?: (s: unknown, errMsg?: string) => T[P]
    }

    function asFactory<T extends object>(keyValidators:KeyValidators<T>) {
    return function (data: unknown, errMsg: string = ""): T {
    console.log(data);
    if (typeof data === 'object' && data !== null) {
    let maybeT = data as T
    for (const key of Object.keys(keyValidators) as Array<keyof T>) {
    keyValidators[key](maybeT[key], errMsg + key + ":");
    }
    return maybeT;
    }
    throw new Error(errMsg + 'data is not an A');
    }
    }

    let data: unknown = JSON.parse('{"a": "yes"}');
    const asA = asFactory<A>({
    a: asString,
    opt: asOptional(asString)
    /// b: asNumber
    })
    let a = asA(data);

    interface B {
    a: A
    }

    const asB = asFactory<B>({
    a: asA
    })

    let data2: unknown = JSON.parse('{ "a": {"a": "yes"} }');
    let b = asB(data2);
    let berr = asB(data);

    Playground Link

    关于 typescript 将未知类型转换为接口(interface)类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58861172/

    49 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com