As front-end technology continues to evolve, typescript has flooded the field of front-end engineers with new life for javascript. I’ll take a look at typescript’s features and its basic syntax.
Why use typescript
Before I get into the syntax of typescript, I feel the need to describe the context in which typescript was born, and it all starts with the programming language type. The main programming languages are strongly or weakly typed, statically or dynamically typed.
Strong typing and weak typing
Strongly typed languages, meaning strongly typed defined languages, do not allow arbitrary implicit conversions. Weakly typed languages, which are languages where data types can be ignored, allow arbitrary implicit typing of data.
Static typing versus dynamic typing
Statically typed languages mean that once a variable is declared, its type is not allowed to change. Dynamically typed languages, in which variables are typed only at runtime and can be changed at any time.
Reasons to use typescript
As you can see from the above classification, javascript is a dynamically weakly typed language, a ‘willful’ and ‘unconventional’ language. As a superset of javascript, typescript is closer to a statically strongly typed language and offers the following programming benefits: 1. Earlier exposure of errors 2. Smarter and more accurate code 3.
Typescript syntax
This chapter focuses on typescript data types, advanced usages of typescript, and typescript modules and declarations.
Typescript data types
TypeScript supports almost the same data types as JavaScript, so we started with ECMAScript 6 (ES6 for short) data types. ES6 data types include: Basic types: number, string, Boolean, symbol, NULL, undefined; Complex types: object (including function, array)
The above code prints out the data types associated with ES6, and the console results are as follows:
The corresponding data types in typescript are as follows:
1, number -> number
As with javascript, all numbers in typescript are floating point numbers, and binary, octal, decimal, and hexadecimal literals are supported
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
Copy the code
2. String -> string
Typescript supports double quotes (“), single quotes (‘), and backquotes (‘) for strings
let one: string = 'abc';
let two: string = "efg";
let three: string = `${one}-${two}`;
Copy the code
3, Boolean -> Boolean
Typescript supports true and false for Boolean
let right: boolean = true;
let wrong: boolean = false;
Copy the code
Null -> null and undefined -> undefined
In TypeScript, both undefined and null have their own types called undefined and NULL. By default, null and undefined are subtypes of all types, but when you specify the strictNullChecks tag, Null and undefined can only be assigned to void and each of them
let u: undefined = undefined;
let n: null = null;
Copy the code
5, array
TypeScript works with array elements just like JavaScript does. There are three ways to define arrays:
(1) Element type []
let list: number[] = [1.2.3];
Copy the code
(2) Array< type >
let list: Array<number> = [1.2.3];
Copy the code
(3) Tuple
The tuple type allows you to represent an array with a known number and type of elements. The elements need not be of the same type.
let list: [string.number] = ['123'.123];
Copy the code
When accessing an element with a known index, the correct type is obtained:
console.log(list[0].substr(1)); // OK
console.log(list[1].substr(1)); // Error, 'number' does not have 'substr'
Copy the code
When accessing an out-of-bounds element, the union type is used instead:
list[2] = 456; // ok, the number can be assigned to the previously defined string or number type, but not to other types
Copy the code
6, the function
(1) Functions in typescript can add a type to each argument and then add the return value type to the function itself
let myAdd = function(x: number, y: number) :number { return x + y; };
Copy the code
(2) Typescript functions are considered valid function types as long as the parameter types match, regardless of whether the parameter names are correct
let myAdd: (baseValue: number, increment: number) = > number =
function(x: number, y: number) { return x + y; }
Copy the code
(3) Functions in typescript must have the same number of arguments and parameters (when no optional arguments, default arguments, or remaining arguments are used)
function buildName(firstName: string, lastName: string) {
return firstName + "" + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
let result2 = buildName("Bob"."Adams"."Sr."); // error, too many parameters
let result3 = buildName("Bob"."Adams"); // ah, just right
Copy the code
(4) Functions in typescript, using? Implement the function of optional parameters, which must be followed by the required parameters
function buildName(firstName: string, lastName? :string) {
if (lastName)
return firstName + "" + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // works correctly now
let result2 = buildName("Bob"."Adams"."Sr."); // error, too many parameters
let result3 = buildName("Bob"."Adams"); // ah, just right
Copy the code
(5) In typescript functions, you can set default values for arguments. Any arguments with default initialization following any required arguments are optional and, like optional arguments, can be omitted when the function is called. Note: Default values and optional parameters cannot be used on the same parameter
function buildName(firstName: string, lastName: string = "Smith") :string {
return firstName + "" + lastName;
}
let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"
let result3 = buildName("Bob"."Adams"."Sr."); // error, too many parameters
let result4 = buildName("Bob"."Adams"); // ah, just right
Copy the code
(6) Functions in typescript can be set to accept zero or more arguments using the ‘… ‘plus the argument array
function buildName(firstName: string. restOfName:string[]) :string {
return firstName + "" + restOfName.join("");
}
let employeeName = buildName("Joseph"."Samuel"."Lucas"."MacKinzie");
Copy the code
7, the object
(1) Use object to declare a non-primitive type, i.e. a type other than number, string, Boolean, symbol, null, or undefined.
let value: object = {}; // ok
value = 123; / / the error,
Copy the code
(2) Use the {} object structure
let value: {first: string.second: number} = {
first: 'abc'.second: 123,}Copy the code
(3) Use the interface interface to define, in the later advanced usage will be explained in detail
8, enum (enumeration)
The enum type is a complement to the JavaScript standard data type. As in other languages such as C#, enumeration types are used to give friendly names to sets of values.
(1) Enumeration of numbers
If no initializer is used, the first value of the enumeration is 0, and the remaining members, if not assigned, have the value of the previous enumeration member plus 1
enum Direction {
Up = 1,
Down,
Left = 10,
Right
} // The value of Right is 11 and the value of Left is 11
Copy the code
(2) String enumeration
In a string enumeration, each member must be a string literal
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",}Copy the code
(3) Heterogeneous enumeration
Enumerations can mix string and numeric members
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",}Copy the code
(4) What does enumeration do
To better understand enumerations, we can look at the js files compiled by TS. For example:When typescript is compiled to javascript, it’s clear that the enumeration actually creates an object that can be referenced in both directionsThis can also be verified by printing from the enumeration of console
9, any
Sometimes we can’t determine the type of the variable, so we just let it pass through the compile phase to keep the type checker from checking the values. We can then mark these variables with the any type
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
Copy the code
Suggestion: Do not use any for all
In the transition from javascript to typescript, many people use any to declare variables. Netizens often call this practice ‘anyscript’. This is fine, but it undermines the original purpose of typescript. It’s not close to a statically strongly typed language. We should be more specific about variable types, or use union types (more on this later in advanced usage), to make our code more intelligent.
10 and void
In some ways, the void type looks like the opposite of any. It means there is no type. When a function does not return a value, you will usually see a return value of type void:
function warnUser() :void {
console.log("This is my warning message");
}
Copy the code
11, never
The type never represents the type of values that will never exist. It can be one of three values:
(1) Raise an error
// A function that returns never must have an unreachable endpoint
function error(message: string) :never {
throw new Error(message);
}
Copy the code
(2) There is no return value type for function expressions or arrow function expressions
// The inferred return value type is never
function fail() {
return error("Something failed");
}
Copy the code
(3) Variables that are bound by type protection that is never true
// A function that returns never must have an unreachable endpoint
function infiniteLoop() :never {
while (true) {}}Copy the code
Advanced uses of typescript
The previous sections have introduced typescript’s basic types, and you should be comfortable with declaring simple types. However, in everyday development, complex object types are the main characters in the code, and typescript makes many changes to them. For example, using interfaces to check object structure; The class types added in ES6 have been further modified to move closer to common static languages; And using generics to increase reusability and so on. Let’s take a look at them.
1. Interface
Interfaces are used to provide structural type checking for complex object types. This is also mentioned in the example above
// use a large hump for interface names and semicolon (;) between variable declarations segmentation
interface ValueOne {
first: number;
second: string;
}
let valueOne: ValueOne = {
first: 123.second: '123',}let valueTwo: {first: number.second: string} = {
first: 123.second: '123',}Copy the code
The valueOne and valueTwo declarations have the same function, but interface can be reused for multiple variables. It is also important to note that interface only provides type checking, not implementation
(1) Optional attributes
Interface can define optional attributes just like function before, but it is not possible to pass in undefined key names (unless type assertions are used, which is not recommended), as shown in the following example:
interfaceCommonValue { first? :number; second? :string;
}
let valueOne: CommonValue = {
first: 123,}let valueTwo: CommonValue = {
second: '123',}let valueThree: CommonValue = <CommonValue>{
third: 123,}/ / complains
Copy the code
(2) Read-only property
Some properties in interface can be set to read-only properties, which can only be changed when the object is created. For example:
interfaceCommonValue { first? :number; second? :string;
readonly third: boolean;
}
let valueOne: CommonValue = {
first: 123.third: true,
}
valueOne.third = false; // error
Copy the code
(3) Can be used to declare functions
In javascript, a function is an object, so it is normal for an interface to declare a function. A function declaration usually contains only a list of parameters and a return value.
interface CombineNames {
(first: string.second: string. res:Array<string>) :string;
}
let getName: CombineNames = (one: string.two: string. rest:Array<string>) :string= > {
let result: string = `${one}-${two}-${rest.length? rest[0] :' '}`;
return result;
}
console.log(getName('abc'.'def'.'hello'.'what'));
Copy the code
(4) Functions in the interface
In interface, you can declare a property as function, which is composed of the name of the property + the list of arguments + the return value.
interface ValueSet {
value: string;
getValue(value: string) :string;
getLowerCaseValue: (value: string) = > string;
}
let valueTwo: ValueSet = {
value: 'ABC'.getValue(value: string) {
return value
},
getLowerCaseValue(value: string) {
returnvalue.toLowerCase(); }}Copy the code
(5) Index signature
In javascript, we can often use the object key name as an index to query the corresponding value. In interface, two index types are supported: number and string. Here’s an example:
interface IndexSetting {
[index: number] :string; // The index name can be defined arbitrarily
}
let valueTwo: IndexSetting = ['123'.'456'];
Copy the code
2) You can use both types of indexes, but the return value of the numeric index must be of the type returned by the string index or its subtype.
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Error: using numeric string index, sometimes get completely different Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
/ / right
interface Okay {
[x: number]: Dog;
[x: string]: Animal;
}
Copy the code
3) When the index signature is common with other attribute names, all value types in interface must be the same
interface NumberDictionary {
[index: string] :number;
length: number; // Yes, length is of type number
name: string // Error, the type of 'name' does not match the type returned by the index type
}
Copy the code
(6) Mixed types
Sometimes you want an object to have multiple types at once. For example, if an object can be used as both a function and an object with additional properties, you can do this:
interface Counter {
(start: number) :string;
interval: number;
reset(): void;
}
function getCounter() :Counter {
let counter = <Counter>function (start: number) {}; counter.interval =123;
counter.reset = function () {};return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
Copy the code
(7) Inheritance between interfaces
If multiple interfaces have parts in common, we can use the extends method to extract the common parts to make the code as simple as possible. Here’s an example:
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
} // An interface can inherit multiple interfaces
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Copy the code
2, class
Before we get into typescript classes, let’s take a look at some of the features of es6 classes: The introduction of the concept of class in THE ES6 specification makes JS developers bid a end to the model of prototype objects imitating object-oriented classes and class inheritance, but there is no real class primitive type in JS, class is just syntax sugar for prototype objects. Let’s look at a simple example
class Test {
value: string;
constructor(value: string) {
this.value = value;
}
getValue() {
return this.value; }}Copy the code
It is equivalent to writing a prototype object like this:
function Test(value) {
this.value = value;
}
Test.prototype.getValue = function () {
return this.value;
};
Copy the code
In the es6 class, we also use static to define static methods or properties, and extend to extend the parent class. For details, see the es6 official document. So what do typescript classes do? First, typescript is compatible with all es6 classes. Then it adds public, private, protected, and readOnly modifiers that are familiar to programmers who use object-oriented methods.
(1) the public
In TypeScript, members are made public by default, indicating that the literal is freely accessible. You can also explicitly designate each member as public.
class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`The ${this.name} moved ${distanceInMeters}m.`); }}Copy the code
(2) private
When a member is marked private, it cannot be accessed outside the class that declared it.
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }}new Animal("Cat").name; Error: 'name' is private.
Copy the code
(3) protected
Protected modifiers behave similar to private modifiers, except that protected members are still accessible in derived classes.
class Person {
protected name: string;
constructor(name: string) { this.name = name; }}class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name)
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is The ${this.name} and I work in The ${this.department}. `; }}let howard = new Employee("Howard"."Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); / / error
Copy the code
(4) readOnly
You can make the property read-only by using the readonly keyword. Read-only attributes must be initialized at declaration time or in the constructor.
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName; }}let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; / / error! Name is read-only.
Copy the code
3, generics
Like languages like C# and Java, typescript uses generics to create reusable components, where a component can support multiple types of data. Let’s take a look at the following example. If we are not sure what type of parameter to pass in, many people would do the following:
function init(value: any) :any {
return value;
}
let initValue: number = init(123);
Copy the code
This is a rough approach, so let’s take a look at how to handle it with generics:
function init<T> (value: T) :T {
return value;
}
let initValue: number = init<number> (123); // Specify the type
let value: string = init('123'); // typescript does type inference
Copy the code
(1) Generic interfaces
We now combine generics with interfaces:
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T> (arg: T) :T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
Copy the code
(2) Generic classes
We now combine generics with class:
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) = > T;
}
let myGenericNumber = new GenericNumber<number> (); myGenericNumber.zeroValue =0;
myGenericNumber.add = function(x, y) { return x + y; };
Copy the code
(3) Generic constraints
If we want the type to contain attributes before the type has been determined, it is problematic to write the following:
function loggingIdentity<T> (arg: T) :T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
Copy the code
In this case, we can use extends for the constraint, which is important and will come in handy for reusable interfaces:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise> (arg: T) :T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
Copy the code
Classes and interfaces love each other
(1) Implements interface
As mentioned above, interface only provides type checking, so can it be used to constrain classes? The answer is yes. Class uses implements to enforce an interface constraint:
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number){}}Copy the code
In angular’s t component s file, it is mandatory to use interfaces to constrain lifecycle methods. A class can also obtain multiple interface constraints:
export class ClassReportComponent implements OnInit.AfterViewInit {
ngOnInit() {}
ngAfterViewInit(){}}Copy the code
(2) Interface extends Class
Can an interface inherit a class in reverse? The answer is yes. When an interface inherits a class type, it inherits the members of the class but not the implementation. It looks like the interface declares the type of all the members that exist in the class, but does not provide the implementation.
class Control {
state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button implements SelectableControl {
state: any = ' ';
select() {};
}
Copy the code
It is important to note here that the interface also inherits from the private and protected members of the class. This means that when you create an interface that inherits from a class that has private or protected members, the interface type can only be implemented by that class or its subclasses. Here’s an example:
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {};
}
Copy the code
(3) Abstract class
An abstract class is a combination of an interface and a class. It has the following characteristics: 1) An abstract class can contain the implementation details of its members, but it cannot be instantiated directly (new).
abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name); }}let a: Department = new Department(); // Error: cannot create an instance of an abstract class
Copy the code
2) An abstract method in an abstract class contains no concrete implementation and must be implemented in a derived class
abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // Must be implemented in a derived class
}
class AccountingDepartment extends Department {
constructor() {
super('Accounting and Auditing'); // Super () must be called in the constructor of a derived class
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports... '); }}let department: Department; // Allow to create a reference to an abstract type
department = new Department(); // Error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // Allow instantiation and assignment of an abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // Error: method does not exist in declared abstract class
Copy the code
5. Type compatibility
Type compatibility in TypeScript is based on structure subtypes, which means that compatibility depends on whether the property values of two variables comply with checking rules. The main discussion here is about complex type compatibility
(1) Object type
The basic rule of TypeScript’s structured type system is that if X is to be compatible with y, y must have at least the same properties as X, that is, the property types of y need to include the property types of X. Here’s an example:
interface Named {
name: string;
}
let x: Named;
// y's inferred type is { name: string; location: string; }
let y = { name: 'Alice'.location: 'Seattle' };
x = y; // ok, y contains the name attribute and is of type string
Copy the code
(2) Function
To determine whether the two functions are compatible, we will only cover the case where only the argument list is different, because there are few other cases. You can check out the typescript official website for more information. Here’s an example:
let x = () = > ({name: 'Alice'});
let y = () = > ({name: 'Alice'.location: 'Seattle'});
x = y; // OK
y = x; // Error, because x() lacks a location property
Copy the code
(3) class
When objects of two class types are compared, only members of the instance are compared. Static members and constructors are not included in the comparison. Here’s an example:
class TestOne {
static type: string = '123';
value: number;
constructor(value: number) {
this.value = value; }}class TestTwo {
static source: number = 123;
value: number;
constructor(value: number) {
this.value = value + 123; }}let testOne: TestOne;
let testTwo: TestTwo;
testOne = testTwo;
testTwo = testOne;
Copy the code
If the target type contains a private member, then the source type must contain a private member from the same class
class TestOne {
private count: number;
static type: string = '123';
value: number;
constructor(value: number) {
this.value = value; }}class TestTwo {
static source: number = 123;
value: number;
constructor(value: number) {
this.value = value + 123; }}let testOne: TestOne;
let testTwo: TestTwo;
testOne = testTwo; // error
testTwo = testOne; // correct
Copy the code
6. Union types and their use
(1) Type assertion
Before we start with union types, let’s look at typescript’s type assertions. Type assertions are like conversions in other languages, but without the special data checking and deconstruction. It has no runtime impact, only at compile time. TypeScript assumes that you, the programmer, have done the necessary checks. It has two forms: 1) Angle bracket syntax
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
Copy the code
2
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
Copy the code
(2) The concept of union type
This is often the case in development, where a variable may have multiple types of values, such as the structure returned by the back end, which is sometimes number, sometimes string, or in a form property selection, where the radio value may be string, and the multi-option value may be an array of multiple strings, So from a development point of view, we can’t determine the value type and we don’t want to take the any form, where the union type comes in handy. Here’s an example:
let value: Array<number | string> | number | string;
// There may be multiple values of value
Copy the code
However, there are many problems with abusing the union type, so let’s introduce two examples
(3) Type protection *
If a value is of a union type, we can only access members that are common to all types of that union type.
interface Father {
sweepFloor(): void;
makeMoney(): void;
}
interface Mother {
cook(): void;
makeMoney(): void;
}
function isWho() :Father | Mother {
return;
}
let person = isWho();
person.makeMoney(); // ok
person.cook(); // error
Copy the code
But the requirement is to implement different methods according to different types, so how can we do that?
interface Father {
sweepFloor(): void;
makeMoney(): void;
}
interface Mother {
cook(): void;
makeMoney(): void;
}
function isWho() :Father | Mother {
return;
}
let person = isWho();
person.makeMoney(); // ok
if((<Mother>person).cook) {
(<Mother>person).cook();
} else if((<Father>person).sweepFloor) {
(<Father>person).sweepFloor();
}
Copy the code
The example above uses a type assertion to enforce the corresponding method, but this method has the downside of requiring a type assertion every time it is used, which can be cumbersome. So can we declare the variable once, and then we don’t have to declare the variable again. In this case, you can use typescript’s type protection
interface Father {
sweepFloor(): void;
makeMoney(): void;
}
interface Mother {
cook(): void;
makeMoney(): void;
}
function isWho(just: boolean) :Father | Mother {
let father: Father = {
sweepFloor: () = > {},
makeMoney: () = >{},}let mother: Mother = {
cook: () = > {},
makeMoney: () = >{},}return just? father: mother;
}
function isFather(person: Father | Mother) :person is Father {
return(<Father>person).sweepFloor ! = =undefined;
}
function isMother(person: Father | Mother) :person is Mother {
return(<Mother>person).cook ! = =undefined;
}
let xiaoMing = isWho(true);
if(isFather(xiaoMing)) {
xiaoMing.sweepFloor();
} else if(isMother(xiaoMing)) {
xiaoMing.cook();
}
Copy the code
In addition to the above, typescript also supports typeof and Instanceof type protection, so you can try it out for yourself.
(4) Seek benevolence and get benevolence *
If there is now a requirement that the parameter type is string or number, and the value of the parameter is returned based on the type of the input parameter, many people think of the combination of function overloading and associative types:
function double(x: number | string) :number | string;
function double(x: any) {
return x + x;
}
Copy the code
But the results were not satisfactory
// const num: string | number
const num = double(10);
// const str: string | number
const str = double('ts');
Copy the code
The result returned is still the associative type, and any subsequent use will still require type assertion or type protection. In this case, we can use the generic + generic constraint method to handle this:
function double<T extends number | string> (x: T) :T;
function double(x: any) {
return x + x;
}
Copy the code
7. Type alias
A type alias, as the name implies, gives a new name to a type. It also means that it can be applied to raw values, union types, tuples, and anything else that requires your handwriting
(1) Basic types
type a = number;
type b = string;
type c = boolean;
type d = symbol;
type e = null;
type f = undefined;
type g = any;
type h = never;
Copy the code
(2) Complex types
All of the complex types mentioned earlier can be represented here by the type alias
type a = () = > number;
type b = Array<number>;
type c<T> = {
name: string; height? :number;
readonly value: T;
}
Copy the code
(3) You can refer to yourself in attributes
You will often use nested trees in your projects, and this is where the type feature comes in handy
type Tree<T> = {
id: number; value: T; children? :Array<Tree<T>> | null;
}
let tree: Tree<number> = {
id: 123.value: 123.children: [{id: 456.value: 456.children: null}}]Copy the code
Of course, the interface can achieve the same effect, so we can choose according to our actual situation
interface Tree<T> {
id: number; value: T; children? :Array<Tree<T>> | null;
}
let tree: Tree<number> = {
id: 123.value: 123.children: [{id: 456.value: 456.children: null}}]Copy the code
Note, however, that the type alias cannot appear anywhere on the right side of the declaration
type Yikes = Array<Yikes>; // error
Copy the code
(4) String literals
String literals allow you to specify the fixed values that a string must have. String literal types work well with union types, type protection, and type aliases.
type Subject = 'math' | 'chinese' | 'english';
function selectSubject(val: Subject) {
val == 'math' && console.log(`select ${val}`);
val == 'chinese' && console.log(`select ${val}`);
val == 'english' && console.log(`select ${val}`);
}
Copy the code
(5) Number literals
In the same way, type also has a numeric literal form
type Num = 1 | 2 | 3 | 4 | 5;
Copy the code
(6) Mapping type
If you want to get a readonly mapping table, you can use keyof and type to do this. If you want to get a readonly mapping table, you can use keyof and type to do this
type ReadonlyItem<T> = {
readonly [key in keyof T]: T[key];
}
type PartialItem<T> = {
[key inkeyof T]? : T[key]; }interface Person {
name: string;
age: number;
}
let d: ReadonlyItem<Person> = {
name: 'james'.age: 18,
}
d.age = 23; // error
let e: PartialItem<Person> = {
name: 'kobe',}// correc
Copy the code
END
About us: We are the front end teaching team of Xiao Education Group, and we are a young team. We support almost all of the group’s teaching operations. Now with the rapid development of the business group, the team is also rapidly expanding, welcome to join us, you are the front end experts ~ we hope you are: solid technical foundation, a field in-depth; Good at precipitation, continuous learning; Personality optimistic, cheerful, lively and outgoing. If you are interested in joining us, please send your resume to: