To get started, see # TypeScript Getting Started.

Today we continue to update several more types

1. The enumeration

Definition 1.

Enum, enumeration. It is used to describe a value that can only be one of a set of named constants

Before type, we used enumerations a lot, but we use them a little less now. Enumerations function similarly to the literal + union type combination and can also represent an explicit set of optional values

2. The format

Enum Enumeration name {The value can be 1 or 2… }

Description:

  1. useenumKeyword definition enumeration
  2. Generally, the first character is capitalized
// Define an enumeration type
enum Direction { Up, Down, Left, Right }

// Use enumeration types
function changeDirection(direction: Direction) {
  console.log(direction)
}

// When calling a function, you should pass in: enumeration of any Direction member
// Like objects in JS, directly through the point (.) The syntax accesses members of the enumeration
changeDirection(Direction.Up)
Copy the code

3. Enumerated values

Unlike the other types in TS, an enumerated type is not just a type, but a value.

  • Type defines a type that has no value:
type NewType = number | string

console.log(NewType)  // The output type is meaningless
Copy the code
  • Enumerations define types that have values:
// Create an enumeration
enum Direction { Up, Down, Left, Right }

// When calling a function, you should pass in: enumeration of any Direction member
// Like objects in JS, directly through the point (.) The syntax accesses members of the enumeration
console.log(Direction.Up) / / 0
Copy the code
  • Using enumerations we can define constants with names. Use enumerations to clearly express intent or to create a differentiated set of use cases. TypeScript supports numeric and string-based enumerations.

4. Enumeration by numbers

  • By default, the value of enumeration is numeric. Default value: a value incremented from 0
  • Of course, you can also initialize values for members of an enumeration
// Defining an initial value after 10 will increment Down -> 11, Left -> 12, and Right -> 13 based on 10
enum Direction { Up = 10, Down, Left, Right }

// Does not apply to values of the self-growing self-timed enumeration type
enum Direction { Up = 2, Down = 4, Left = 8, Right = 16 }
Copy the code

5. String enumeration

  • String enumeration: The value of an enumeration member is a string
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}
Copy the code

Note: String enumerations have no self-growth behavior, so each member of a string enumeration must have an initial value

7. Summary

  1. Enumerations are similar to the literal type + union type combination described in the previous article in that they represent an explicit list of optional values
  2. In general, the combination of literal types and union types is recommended because it is more intuitive, concise, and efficient than enumerations

2.any

1. Function of the any type

Sometimes we want to specify a type for variables whose type is not known at programming time. These values may come from dynamic content, such as user input or third-party code libraries. In this case, we don’t want the type checker to check these values and just pass them through compile-time checks. We can then mark these variables with type any:

 // Define the notSure variable to be of type any
let notSure: any = 4
notSure = 'maybe a string instead'
notSure = false
Copy the code

The any type is also useful when you only know part of the data type. For example, you have an array that contains different types of data:

// List is an array. The values in an array are of any type
let list: any[] = [1.true."free"]
list[1] = 100;
Copy the code

2. The implicit any)

Default to any when no type is declared:

  1. Declared variables do not provide a type or a default value
  2. When defining functions, arguments are not given types

Type assertion

Sometimes you’ll find that you know more about a value than TypeScript does. Usually this happens when you clearly know that an entity has a more exact type than its existing type. Type assertions are a way of telling the compiler, “Trust me, I know what I’m doing.” Type assertion is like conversion in other languages, but without special data checking and deconstruction. It has no run-time impact, only at compile time. TypeScript assumes that you, the programmer, have done the necessary checks.

1. The format

Key words: AS

Const variable = value as type

2. Application scenarios

Here’s the code: Suppose we explicitly know that there is an IMG on the page and its ID is img.

const box = document.getElementById('img')
console.log(box.src) / / ts an error
Copy the code

The return value of the above method is HTMLElement. This type only contains attributes or methods common to all tags. It does not contain attributes or methods unique to img tags such as SRC. At this point we modify the above code with type assertions:

// The img tag is of type HTMLImageElement
const box = document.getElementById('img') as HTMLImageElement
console.log(box.src)  // No error was reported
Copy the code

The type after the as keyword should be a more specific type (HTMLImageElement is a subtype of HTMLElement)

A tip to get the type of DOM element: Google Chrome as an example

  1. Click the arrow in the upper left corner of the debugger, find the element you want to query in the web page, and click
  2. Output at the console$0.__proto__You can see the current DOM type

3.typeof

The typeof operator is provided to get the typeof data in JS:

console.log(typeof 'Hello world')
Copy the code

TS also provides typeof operators: types that can refer to variables or attributes in a type context (type queries)

1. Application scenarios

From the value of an existing variable, deduce the type to obtain the value backwards to simplify type writing

2. The format

Type Type = typeof Constant

Example 3.

const res = { name: 'Give me a div.'.city: 'wuhan'.skills: ['js'.'css'] }

type Stu = typeof res

function fn(obj:Stu) {
    // write obj here to get a hint
    obj.skills
}

fn(res)
Copy the code

4. The generic

In software engineering, it is important not only to create consistent, well-defined apis, but also to consider reusability. The ability of components to support not only current data types but also future data types gives you a lot of flexibility when building large systems

Generics, as the name suggests, can be applied to multiple types, and using type variables such as T helps us catch incoming types, which we can then continue to use. The nature of a parameterized type is that the data type being operated on is specified as a parameter. This parameter type can be used in the creation of classes, interfaces and functions, respectively, as generic classes, generic interfaces and generic functions

1. Generic functions

1.1 Format for creating generic functions

function fn<Type> (value: Type) :Type { return value }
// The Type above is just a name, it can be changed to something else

function fn<T> (value: T) :T { return value }
Copy the code

Syntax: After the function name, write <>(Angle brackets) to add Type variables, such as Type here.

  1. The Type variable, Type, is a special Type of variable that handles types rather than values
  2. This type variable acts as a type container that captures the user-supplied type (which type is specified by the user when the function is called)
  3. Because Type is a Type, it can be used as the Type of both the function parameter and the return value, indicating that the parameter and return value have the same Type
  4. The Type variable Type can be any valid variable name

1.2 Format for calling generic functions

const num = fn<number>(10)
const str = fn<string>('a')
Copy the code
  1. Syntax: Add after the function name<>Angle brackets,Angle brackets specify the specific type, for example, number here
  2. When the Type number is passed in, it is captured by the Type variable Type specified when the function is declared
  3. In this case, the Type of Type is number, so the parameter and return value of the fn function are also of Type number
  • Similarly, if the type string is passed in, both the function ID parameter and the return value are of type String
  • In this way, generics allow the ID function to work with many different types, enabling reuse while ensuring type-safety

1.3 Type inference simplifies function calls

function fn<T> (value: T) :T { return value }
// omit 
      
        to call the function
      
let num = fn(10)
let str = fn('a')
Copy the code
  1. When a generic function is called, it can be simplified by omitting the < type >
  2. At this point, TS uses a mechanism called Type parameter inference internally (understand Type inference) to automatically infer the Type of the Type variable Type from the arguments passed in
  3. For example, if you pass in the argument 10, TS will automatically infer the Type number of the variable num as the Type of Type

2. Generic constraints

By default, the type variable T of a generic function can represent more than one type. This makes it impossible to access any properties, for example, fn(‘a’) gets the length of the argument when calling the function:

function fn<T> (value: T) :T {
  // there will be no prompt for value
  console.log(value.length)// There will be an error
  return value
}
fn('a')
Copy the code
  • Type can represent any Type. There is no guarantee that length exists. For example, the number Type does not have length
  • At this point, you need to add constraints to the generic to shrink the type (narrow the type range)

Add generic constraints

There are two main ways to add generic constraint contraction types:

  1. Specify a more specific type
  2. Adding constraints
1. Specify a more specific type

For example, : can accept arrays of any type.

Change the Type to Type[](array of Type), because any array must have the Length attribute and is therefore accessible

function fn<Type> (value: Type[]) :Type[] {
  console.log(value.length)
  return value
}
Copy the code
2. Add constraints

For example, passing in type T must have a length attribute.

// Create an interface
interface ILength { length: number }

// T extends ILength adds a generic constraint
function fn<T extends ILength> (value: T) :T {
  console.log(value.length)
  return value
}

fn('abc') // Ok
fn([1.2.3]) // Ok
Copy the code

Explanation:

  1. Create an interface ILength that describes the constraint and requires the length attribute
  2. throughextendsThe keyword uses this interface to add constraints to generics (type variables)
  3. This constraint says: The type passed in must have the Length attribute
  • Note: Arguments passed in (for example, arrays) need only have a length attribute (type compatibility)

3. Multiple type variables

Generics can have multiple type variables, and there are constraints between type variables (e.g., the second type variable is bound by the first type variable). For example, create a function to get the value of an attribute in an object:

function getProp<Type.Key extends keyof Type> (obj: Type, key: Key) {
  return obj[key]
}
let person = { name: 'jack'.age: 18 }
getProp(person, 'name')
Copy the code

Explanation:

  1. A second type variable Key was added to be used between two type variables.Comma separated.
  2. The keyof keyword takes an object type and generates a combined type of its key name, which may be a string or number.
  3. In this examplekeyof TypeWe actually get the combined type of all the keys of the Person object, i.e. :'name' | 'age'
  4. The Type variable Key is bound by Type. Key can only be any of the keys of Type, or it can only access attributes that exist in the object
// Type extends Object means that Type should be an object Type. If it is not an object Type, an error is reported

function getProperty<Type extends object.Key extends keyof Type> (obj: Type, key: Key) {
  return obj[key]
}

getProperty({a:1.b:2}, 'a')
Copy the code

4. Generic interfaces

Use generics in interfaces to increase their flexibility and reusability


interface CreateArrayFunc<T> {
    (length: number, value: T): Array<T>;
}

let createArray: CreateArrayFunc<any>;
createArray = function<T> (length: number, value: T) :Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3.'x'); // ['x', 'x', 'x']
Copy the code
  1. Add it after the interface name< type variable >, the interface becomes a generic interface.
  2. The type variable of an interface is visible to all other members of the interface, that is, all members of the interface can use type variables.
  3. When using generic interfaces, specific types need to be explicitly specified

5. Generic tools

Generic tool types :TS has some common tool types built in to simplify common operations in TS

Note: They are all implemented based on generics (generics are more generic for many types) and are built in and can be used directly in your code. There are many types of these tools, and this blog introduces three of them:

1.Partial

Partial is used to create a new Type based on a Type in which all properties are optional. format

type OldType = {}
type newType = Partial <OldType>
Copy the code

The sample

To construct (create) a Type that sets all properties of Type to optional? .

type Props =  {
  id: string
  children: number[]
}

type PartialProps = Partial<Props>
Copy the code

The new PartialProps type is constructed with the same structure as Props, but all properties become optional.

2.Readonly

Readonly

is used to construct a Type that sets all properties of Type to Readonly.

type Props =  {
  id: string
  children: number[]
}

type ReadonlyProps = Readonly<Props>
Copy the code

The new type ReadonlyProps has the same structure as Props, but all properties are read-only.

let props: ReadonlyProps = { id: '1'.children: []}// Error demonstration
props.id = '2'
Copy the code
  • When we try to reassign the id attribute, we get an error: “ID” cannot be assigned because it is read-only.

3.Pick

Pick

selects a set of attributes from Type to construct a new Type.
,>

type Props = {
  id: string
  title: string
  children: number[]
}
type PickProps = Pick<Props, 'id' | 'title'>
Copy the code

Explanation:

  1. The Pick tool type has two type variables: 1 for which properties to select and 2 for which properties to select. For the second type variable, only the property name is passed if only one is selected.
  2. The second type variable can only pass in an attribute that exists in the first type variable.
  3. The new type PickProps is constructed with only the id and title property types.

Getting started with TypeScript