【问题标题】:Please explain this typescript syntax involving generics and type alias请解释这个涉及泛型和类型别名的打字稿语法
【发布时间】:2020-10-06 08:36:56
【问题描述】:

我正在尝试学习一些教程,但我在理解 typescript 语法方面遇到了困难。请提供对以下打字稿语法的解释

1

type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;

我在 typescript 手册的泛型章节中找不到一个示例,该示例描述了上述语句的 &lt;T, U&gt; 部分 - 这是什么意思?这是否意味着T 是输入而U 是输出?

我理解部分但似乎无法理解 Partial&lt;{ [Key in keyof T]: U }&gt; 请解释它的含义

2

type Validation<T, U> = (fields: T) => ValidationResult<T, U>; 

上述语句是否为接受类型T并返回ValidationResult&lt;T, U&gt;的函数定义类型别名?

U 代表什么?

3

const hasLength = <T>(len: number, input: string | Array<T>) =>
input.length >= len;

const hasUserName = (input: string) =>
hasLength(1, input) ? true : "Name is required.";

&lt;T&gt;(len: number, input: string | Array&lt;T&gt;) 代表什么?

上述声明中前面的&lt;T&gt; 是什么意思?

你能解释一下上面两个声明是什么意思吗?

以上两个声明const hasLengthconst hasUserName是什么关系?

4

const fieldValues = {
    name: "Test User",
    level: 10,
    description: "Test Description"
};

type FieldValues = typeof fieldValues;

const validationRules = [
    ({ name }: FieldValues) => ({
        name: hasUserName(name)
    }),
    ({ description }: FieldValues) => ({
        description: hasValidDescription(description)
    })
];

我知道const fieldValues 被分配了一个对象字面量,因此fieldValues 的值将是

{
    name: "Test User",
    level: 10,
    description: "Test Description"
}

现在,type FieldValues = typeof fieldValues; 行是什么意思?

上述声明中使用typeof有什么意义?

同时解释该语句后面的代码块

TIA!

【问题讨论】:

    标签: typescript


    【解决方案1】:

    1

    type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;
    

    在这个例子中,U 是一个泛型 - 所以它代表任何类型。在使用类型时定义这些泛型:

    type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;
    
    type TestType = {
        a: string,
        b: number,
    };
    
    const x: ValidationResult<TestType, string> = {
        a: 'test1',
        b: 'test2',
    };
    
    const y: ValidationResult<TestType, string> = {
        a: 'test1',
        // @ts-expect-error
        c: 'test3',
    };
    

    Playground Link. 所以ValidationResult 类型定义了一个类型,该类型将具有来自T 类型的任意数量的键,并且这些键将具有U 类型的值,无论定义为什么。

    2

    type Validation<T, U> = (fields: T) => ValidationResult<T, U>;
    

    你是对的; Validation 是一种函数类型,它接受T 类型的一些值,并返回一个ValidationResult&lt;T, U&gt;;本例中U定义如上,当使用类型时:

    type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;
    
    type TestType = {
        a: string,
        b: number,
    };
    
    type Validation<T, U> = (fields: T) => ValidationResult<T, U>;
    
    const f1: Validation<TestType, number> = fields => ({ a: 2, b: 3 });
    // @ts-expect-error
    const f2: Validation<TestType, number> = fields => ({ c: 4 });
    

    Playground link.

    3

    const hasLength = <T>(len: number, input: string | Array<T>) =>
        input.length >= len;
    
    const hasUserName = (input: string) =>
        hasLength(1, input) ? true : "Name is required.";
    

    &lt;T&gt;(len: number, input: string | Array&lt;T&gt;) 正在定义函数的参数: 1.len是一个数字 2.inputstringArray&lt;T&gt;的联合类型;意思是,它要么是字符串,要么是某种类型的数组T;这两种类型都有一个可以使用的length 属性。

    前导T 是泛型;它代表某种类型;我们只是说我们不想在函数中定义该类型是什么,它可以是任何东西。

    hasLengthhasUserName的关系是后者使用前者来检查用户名是否至少是一个字符。 Typescript 可以知道,当hasUserNameinput 作为第二个参数调用hasLength 时,hasLength 中的T 将是一个字符串。

    4

    const fieldValues = {
        name: "Test User",
        level: 10,
        description: "Test Description"
    };
    
    type FieldValues = typeof fieldValues;
    
    const validationRules = [
        ({ name }: FieldValues) => ({
            name: hasUserName(name)
        }),
        ({ description }: FieldValues) => ({
            description: hasValidDescription(description)
        })
    ];
    

    typeof 是一个打字稿关键字,它采用值的类型。所以FieldValues 实际上是一个看起来像这样的类型:

    type FieldValues = {
        name: string;
        level: number;
        description: string;
    };
    

    下一个代码块定义了一个函数数组,这些函数接受一个FieldValues 对象,并返回一个对象。对象上的键指示fieldValues 对象是否对某些属性有效。我猜他们用它来验证一些字段。

    【讨论】:

    • 你能解释一下为什么他们把这个用括号括起来吗? =&gt; ({ name: hasUserName(name)})?为什么不=&gt; {name: hasUserName(name)}
    • @blogs4t 当然——那部分是相当标准的 javscript,没有括号,你会得到一个语法错误;你必须拥有它们才能返回一个对象
    【解决方案2】:

    对于初学者,“泛型”也称为“参数多态性”,第一个类型参数通常称为“T”(用于 Type),任何附加参数只是按字母顺序排列的下一个字符(T、U、V... )。

    1) 部分类型

    Partial Types 允许您构造一个新类型,具有 T 的所有属性,但它们是可选的,可以缺少。

    type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;
    

    这意味着,“我从 T 创建了一个具有类型 U 的所有属性的类型”。例如ValidationResult&lt;MyType, string&gt; 将包含来自“MyType”的所有字符串属性。

    注意:[name-expression]: type 称为“计算属性”。

    interface Test{
        foo: string,
        bar: number
    }
    
    type ValidationResult<T, U> = Partial<{ [Key in keyof T]: U }>;
    
    let v: Baz<Test, string> = { foo: 't', bar: 1 }; // Error! bar is not a string!
    

    2) 函数类型

    type Validation<T, U> = (fields: T) => ValidationResult<T, U>; 
    

    'Validation' 是一个函数类型,它接受某个类型 T 并返回一个包含 T 中所有类型为 U 的属性的部分类型。

    所以返回类型是我们之前定义的,但是这个函数只是给了我们这些ValidationResults之一。

    3) 联合类型和匿名函数

    const hasLength = <T>(len: number, input: string | Array<T>) =>
    input.length >= len;
    

    所以这是一个匿名函数(或“lambda”):

    (len: number, input:string) => input.length >= len
    

    这是一个从(数字,字符串)到布尔值的函数。 &lt;T&gt; 是一个类型参数,所以它是一个泛型 lambda!

    <T>(n: number, T: x) => doSomething...
    

    string | number | T 形式的类型是 union type,即它可以采用每个列出的类型中允许的任何值:'abc' 或 123 或任何 T 是...

    所以 'hasLength' 是一个 (lambda) 函数,它将 'len' 与 Ts 参数的字符串或数组的长度进行比较。

    const hasUserName = (input: string) =>
    hasLength(1, input) ? true : "Name is required.";
    

    这只是使用上面的函数并传递一个字符串作为参数。您也可以致电:

    hasLength(1, ['a', 'b'])
    

    即'hasLength of number, Array'。

    4) 匿名类型

    所以就像你说的,我们将一个对象字面量分配给我们的常量。但是常量的类型是什么?最通用的可能是“对象”,但这根本没有用!

    'typeof' 运算符为我们提供了对象的类型。即使我们从未定义过接口或类,也没有给这个对象命名,我们已经将它的(未命名的)类型放入变量“FieldValues”中。 然后我们可以使用该类型:

    const validationRules = [
        ({ name }: FieldValues) => ({
            name: hasUserName(name)
        }),
        ({ description }: FieldValues) => ({
            description: hasValidDescription(description)
        })
    ];
    

    这是一个包含函数的数组(参见[])。该函数使用一种公认的奇怪语法来表示,它接受一个名为 'name' 且类型为 'FieldValues' 的对象并返回一个对象。

    【讨论】:

    • ({ name }: FieldValues) 是否代表对象解构..?
    猜你喜欢
    • 2021-10-27
    • 1970-01-01
    • 2021-11-26
    • 2019-01-25
    • 2020-01-23
    • 2017-09-15
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    相关资源
    最近更新 更多