简体   繁体   中英

Please explain this typescript syntax involving generics and type alias

I am trying to follow some tutorials and i have difficulties in understanding typescript syntax. Kindly provide an explanation to the following typescript syntax

1

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

I could not find an example in the generics chapter in typescript handbook that describes something like <T, U> part of the above statement - what does it mean? does it mean T is input and U is output?

I understand Partial but can't seem to understand Partial<{ [Key in keyof T]: U }> please explain what it means

2

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

Does the above statement define a type alias for a function that accepts a type T and returns a ValidationResult<T, U> ?

What does the U represent?

3

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

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

What does <T>(len: number, input: string | Array<T>) represent?

what does the leading <T> mean in the above declaration?

Can you explain what the above two declarations mean?

What is the relationship between the above two declarations const hasLength and const 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)
    })
];

I understand const fieldValues is assigned with an object literal and hence fieldValues value will be

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

Now, what does the line type FieldValues = typeof fieldValues; mean?

What is the significance of using typeof in the above declaration?

Also explain the block of code that follows that statement

TIA!

For starters, "generics" are also called "parametric polymorphism" and the first type parameter is often called 'T' (for Type), any additional parameter is just the alphabetically next character (T, U, V...).

1) Partial Types

Partial Types allow you to construct a new type, with all the properties of T, but they are optional and can be missing.

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

This means, "I create a type from T with all the properties of type U". For example ValidationResult<MyType, string> would contain all string properties from 'MyType'.

Note: the [name-expression]: type is called 'computed property'.

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) Function type

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

'Validation' is a function type that takes some type T and returns a partial type that contains all the properties from T that have type U.

So the return type is what we defined before, but this function just gives us one of these ValidationResults.

3) Union types and anonymous functions

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

So this is an anonymous function (or "lambda"):

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

This is a function from (number, string) to boolean. The <T> is a type parameter, so it's a generic lambda!

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

A type of the form string | number | T string | number | T string | number | T is a union type , ie, it may take any value allowed in each of the listed types: 'abc' or 123 or whatever T is...

So 'hasLength' is a (lambda) function that compares 'len' to the length of the string or Array of Ts argument.

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

This just uses the above function and passes a string as argument. You could also call:

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

That is 'hasLength of number, Array'.

4) Anonymous types

So like you said, we assign an object literal to our constant. But what's the type of the constant? The most general would probably be 'object', but that's not useful at all!

The 'typeof' operator gives us the type of our object. Even though we have never defined an interface or a class and we haven't given a name to this object, we have gotten it's (unnamed) type into the variable 'FieldValues'. Then we can use that type:

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

This is an array (see the [] ) containing functions. The function uses an admittedly strange syntax to say, that it takes an object named 'name' of type 'FieldValues' and it returns an object.

1

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

In this example U is a generic - so it represents any type. You define these generics when you use the type:

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. So the type ValidationResult defines a type which will have any number of keys from type T , and those keys will have values of type U , whatever that is defined as.

2

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

You are right; Validation is a type of function, which takes some value of type T , and returns a ValidationResult<T, U> ; U in this example is defined as above, when the type is used:

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.";

<T>(len: number, input: string | Array<T>) is defining the arguments of the function: 1. len is a number 2. input is a union type of string and Array<T> ; meaning, it's either a string or an array of some type T ; both of these types have a length property which can be used.

The leading T is a generic; it represents some type; we're just saying that we don't want to define what that type is in the function, it could be anything.

The relationship between hasLength and hasUserName is that the latter uses the former to check whether the username is at least one chatacter. Typescript can know that when hasUserName calls hasLength with input as the second argument, T in hasLength will be a string.

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 is a typescript keyword that takes the type of a value. So FieldValues is actually a type which would look like:

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

The next block of code defines an array of functions which take in a FieldValues object, and return an object. The key on the object indicates whether the fieldValues object is valid for some property. I'm guessing they use this to validate a number of fields.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM