【问题标题】:Using a user-defined object as types in TypeScript在 TypeScript 中使用用户定义的对象作为类型
【发布时间】:2019-11-21 06:10:05
【问题描述】:

我在这种情况下,我不知道类型会是什么样子,无论是未定义的还是布尔值、字符串还是数字等。我正在开发一个库,它将解析一些字符串内容并返回用户使用“类型对象”描述的属性对象。

Type 是类型对象应该是什么样子的接口,它是这样的:

/**
 * A type object.
 */
export default interface IType<O>
{
    /** The name of the type. */
    name: string;

    /** A description of the type. */
    description?: string;

    /**
     * Parse the given input content and return the parsed output value.
     * @param input The given input value.
     * @returns The parsed output.
     */
    parse(input: string): O;
}

我为用户提供了 3 个遵循此接口的预定义“类型对象”(Number 作为 numberType,Boolean 作为 booleanType,String 作为 stringType)。用户可以使用这些类型从字符串中收集参数。

参数接口定义了如何在代码中指定参数。

/**
 * An object describing how an argument will look like.
 */
export default interface IArg<T>
{
    /**
     * The name of the argument, this is how you use the argument later
     * in the command object.
     */
    name: string;

    /** A description about the argument. */
    description?: string;

    /** The type the argument should be resolved with. */
    type: IType<T>;

    /** Should this take all the parameters left of the string? */
    rest?: boolean;

    /** Is the argument required? */
    required?: boolean;
}

用户创建一个命令类并将一些参数传递给构造函数,包括一个参数数组;

[
    {
        name: "age"
        type: numberType
    },
    {
        name: "name",
        type: stringType
    }
]

解析命令字符串时,这些参数将被添加到对象input.args 中。不知何故,我希望打字稿解析器知道用户提供的信息可能提供或不提供什么。

例如如果需要一个参数并且是IArg&lt;string&gt; 的类型(我们称之为name),那么解析器知道input.args.name 肯定是一个字符串,但如果不需要,它可能是未定义的或字符串。

这有可能实现吗?

编辑:我找到了thisjcalz 的答案,它接受了一个键值对对象,这正是我正在寻找的;但我不确定如何用数组实现它。

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    这是我想出的:

    首先从您的接口定义中删除required 参数。原因很快就会显现出来:

    interface IArg<T> {
        /**
         * The name of the argument, this is how you use the argument later
         * in the command object.
         */
        name: string;
    
        /** A description about the argument. */
        description?: string;
    
        /** The type the argument should be resolved with. */
        argType: IType<T>;
    
        /** Should this take all the parameters left of the string? */
        rest?: boolean;
    };
    

    现在我使用这个人为设计的 token 解析器示例,它应该仅在需要或可用(即不为 null)时解析令牌。

    // Used to check if the IArg has a required parameter that is set to true
    function argIsRequired(arg: IArg<unknown> & {required?: boolean}): boolean {
        return arg.required === true;
    }
    
    function parseToken<T>(token: string, decodeToken: IArg<T> & { required: true }): T;
    function parseToken<T>(token: string, decodeToken: IArg<T>): T | undefined;
    function parseToken<T>(token: string | null, decodeToken: IArg<T>) {
        if (token == null) {
            if (argIsRequired(decodeToken)) {
                throw Error("required token not found");
            } else {
                return undefined;
            }
        }
        return decodeToken.argType.parse(token);
    }
    

    函数重载的目的是帮助类型检查器决定是否允许某些返回类型(T vs T | undefined)。

    通过从IArg 接口中删除required 参数,我们现在可以在解析器函数中专门化它以充当函数的类型保护。

    现在进行测试,我们定义了两个可能的参数,其中一个是必需的,另一个不是:

    const ageArg = new class implements IArg<number> {
        readonly name = "age"
        readonly argType = numberType;
        readonly required = true;
    };
    
    const nameArg = new class implements IArg<string> {
        readonly name = "name"
        readonly argType = stringType;
    };
    

    如果上面的定义是正确的,如果我们尝试对上面parseToken函数返回的值使用错误的类型,类型检查器应该会给我们一个错误。

    const age: number = parseToken('24', ageArg); // This is Ok
    // const name: string = parseToken("", nameArg); // This gives error
    const name: string | undefined = parseToken("", nameArg); // This is Ok
    

    Playground link

    【讨论】:

    • 谢谢,虽然解析参数并不是真正的问题,但问题是如何让打字稿解析器知道input.args对象中有哪些属性可用。
    【解决方案2】:

    【讨论】:

      猜你喜欢
      • 2016-12-02
      • 2023-03-04
      • 2020-03-25
      • 2019-12-21
      • 2019-10-12
      • 1970-01-01
      • 2021-01-29
      • 2019-10-06
      • 1970-01-01
      相关资源
      最近更新 更多