1. Does it work?
nature
- Is a JavaScript with type annotations added
- Does not break JavaScript’s original body of knowledge
More reliable
- TypeScript’s static type detection can find and resolve low-level errors during development
Interface oriented programming
Such as:
interface UserInfo { name: string; age: number; avatar? : string; } function getUserInfo(props: UserInfo) { ... }Copy the code
- Change your way of thinking and develop a good coding habit
The mainstream
- React, Vue 3, Angular, Deno, Nest.js, etc., either source in TypeScript or provide perfect support for TypeScript.
2. Basic grammar
:
A separator used to separate variables from types
let num: number = 6
Copy the code
Static type detection
Statically typed programming languages can accurately detect type errors at compile time, which is the advantage of static type checking.
Array type (Array)
Defines an array type using the form []
/** The child elements are arrays of numeric type */
let array1: number[] = [1.2.3];
/** The child element is an array of type string */
let array2: string[] = ['x'.'y'.'z'];
Copy the code
Use Array generics to define Array types
/** The child elements are arrays of numeric type */
let array1: Array<number> = [1.2.3];
/** The child element is an array of type string */
let array2: Array<string> = ['x'.'y'.'z'];
Copy the code
Tuple Type
The most important feature of tuples is that they can limit the number and type of array elements, which makes them particularly suitable for multi-value returns.
any
Any refers to an arbitrary type, which is an official cheat that selectively circumvents static type detection
unknown
Unknown is a type added in TypeScript 3.0 to describe variables of uncertain type. Temporary variables that can be used to receive different types of return values under different conditions
let result: unknown;
if (x) {
result = x();
} else if (y) {
result = y();
}
Copy the code
Unlike any, unknown is more secure on types. For example, we can assign a value of any type to unknown, but a value of unknown type can only be assigned to unknown or any
let result: unknown; let num: number = result; // prompt ts(2322) let anything: any = result; // No error will be displayedCopy the code
When unknown is used, TypeScript does type checking for it. However, without Type Narrowing, any operation we perform on Unknown will have the following error:
let result: unknown; result.toFixed(); / / hint ts (2571).Copy the code
All type reduction methods are valid for Unknown,
let result: unknown; if (typeof result === 'number') { result.toFixed(); // the hover result type is number.Copy the code
Void, undefined, null
Void, which applies only to functions that have no return value. That is, if the function returns no value, it is of type void.
never
Never indicates the type of value that never occurs
object
The object type is non-primitive type, that is, non-number, string, Boolean, bigint, symbol, NULL, undefined type
Type Assertion
Casting, like casting only at the type level, tells TypeScript to do type checking the way we do. Use the AS syntax for type assertion
const arrayNumber: number[] = [1, 2, 3, 4];
const greaterThan2: number = arrayNumber.find(num => num > 2) as number;
Copy the code
Use Angle bracket + type format for type assertion
const arrayNumber: number[] = [1, 2, 3, 4];
const greaterThan2: number = <number>arrayNumber.find(num => num > 2);
Copy the code
There is no difference between the two methods, but the Angle bracket format will cause syntactic conflicts with JSX, so as is preferred. Use the literal value + as const syntax structure for constant assertions
/** let STR = 'STR' as const; /** readOnlyArr is' readOnlyArr [0, 1]' */ const readOnlyArr = [0, 1] as const;Copy the code
A special nonempty assertion that adds ‘! To the end of a value (variable, attribute) ‘assertion operator, which can be used to exclude null, undefined
let mayNullOrUndefinedOrString: null | undefined | string; mayNullOrUndefinedOrString! .toString(); // ok mayNullOrUndefinedOrString.toString(); // ts(2531) // For non-empty assertions, we should also consider it as dangerous as any.Copy the code
3. Literal typing, type inference, type widening, and type narrowing
Type inference
{ let x1 = 42; Let x2: number = x1; // ok }Copy the code
Context inference
Type Adder = (a: number, b: number) => number; const add: Adder = (a, b) => { return a + b; } const x1 = add(1, 1); Const x2 = add(1, '1'); // ts(2345) Argument of type '"1"' is not assignable to parameter of type 'number }Copy the code
Literal type
In TypeScript, literals can represent not only values but also types, known as literal types.
Currently, TypeScript supports three literal types: string literals, number literals, and Boolean literals, each of which has the same literal type as its value
{
let specifiedStr: 'this is string' = 'this is string';
let specifiedNum: 1 = 1;
let specifiedBoolean: true = true;
}
Copy the code
A literal type is a subtype of a collection type, which is a more concrete representation of the collection type. For example, ‘this is string’ (which represents a string literal type) is of type string (or rather a subtype of string), And string doesn’t have to be the ‘this is String ‘type
{ let specifiedStr: 'this is string' = 'this is string'; let str: string = 'any string'; specifiedStr = str; // ts(2322) type '"string"' cannot be assigned to type 'this is string' STR = specifiedStr; // ok }Copy the code
String literal type
Use a string literal type as the type of the variable
let hello: 'hello' = 'hello';
hello = 'haha'; // ts(2322) Type '"haha"' is not assignable to type '"hello"'
Copy the code
The application scenario is that multiple literal types can be combined into a single union type to describe a practical collection with explicit members
type Direction = 'up' | 'down';
function move(dir: Direction) {
// ...
}
move('up'); // ok
move('left'); // ts(2345) Argument of type '"left"' is not assignable to parameter of type 'Direction'
Copy the code
Numeric literal types and Boolean literal types
/ / the joint type of the function of using a combination of literal parameters are limited to a more specific type interface Config {size: 'small' | 'big'; isEnable: true | false; margin: 0 | 2 | 4; }Copy the code
Literal design (Refinement of Literal types)
All variables defined by let or var, function parameters, and non-read-only attributes of an object that meet the conditions for specifying an initial value and not explicitly adding a type annotation, infer the type of the specified initial value literal-type broadening. This is literal-type broadening.
{ let str = 'this is string'; // Type is string const specifiedStr = 'this is string'; // The type is 'this is string'}Copy the code
Type KP
To broaden the null, and undefined type, through the let, var variables defined if meet not explicitly declared type annotation and endowed with null or undefined values, then deduce the type of these variables is any:
{ let x = null; // let y = undefined; / / type to broaden into any / * * -- -- -- -- -- line -- -- -- -- -- -- -- * / const z = null; // Type is null}Copy the code
Type Narrowing.
Reduce the type of a variable from a broad set to a relatively small, unambiguous set by some operation
You can use type guards to narrow the type of a function parameter from any to an explicit type
{ let func = (anything: any) => { if (typeof anything === 'string') { return anything; Else if (typeof anything === 'number') {return anything; // Type is number} return null; }; }Copy the code
4. Function types
Return value type
The value => in a function type is used to represent the definition of the function. The parameter type of the function is on the left and the return value type of the function is on the right
type Adder = (a: number, b: number) => number; Const add: Adder = (a, b) => a + b; // ES6 arrow functionCopy the code
In addition to using this declaration syntax in objects, we can also use a shorthand syntax similar to object attributes to declare properties of function types
interface Entity { add: (a: number, b: number) => number; del(a: number, b: number): number; } const entity: Entity = { add: (a, b) => a + b, del(a, b) { return a - b; }};Copy the code
Default and inferred return value types
function computeTypes(one: string, two: number) { const nums = [two]; Const STRS = [one] return {nums, STRS} // Return {nums: number[]; STRS: string[]}Copy the code
Type inference of function return values combined with generics enables particularly complex type calculations, such as the association of State, Reducer, and Effect types in the Redux Model.
The return value of the Generator function
Generator functions return an Iterator object. We can use generics of Generator’s name or Iterator’s name to indicate the type of the returned value (Generator types inherit from Iterator types).
type AnyType = boolean; type AnyReturnType = string; type AnyNextType = number; function *gen(): Generator<AnyType, AnyReturnType, AnyNextType> { const nextValue = yield true; Return '${nextValue}'; // Mandatory string type}Copy the code
Optional and default parameters
function log(x? : string) { return x; } log(); // => undefined log('hello world'); // => hello worldCopy the code
Add? Before: of the type annotation. The parameter x representing the log function is defaultable.
The default parameter type of a function must be a subtype of the parameter type
function log3(x: number | string = 'hello') {
console.log(x);
}
Copy the code
The remaining parameters
function sum(... nums: number[]) { return nums.reduce((a, b) => a + b, 0); }Copy the code
this
Declare the object to which this refers (how the function is called) in the first argument to the function, as in the simplest case, the this pointer to the object’s method
function say(this: Window, name: string) {
console.log(this.name);
}
window.say = say;
window.say('hi');
const obj = {
say
};
obj.say('hi'); // ts(2684) The 'this' context of type '{ say: (this: Window, name: string) => void; }' is not assignable to method's 'this' of type 'Window'.
Copy the code
Note that if we call say() directly, this would actually point to the global variable window, but TypeScript doesn’t know who called say, so we default this to void, which causes a TS (2684) error.
When defining a function property of an object, TypeScript can detect errors as long as the reference to this is different in the actual call
interface Person { name: string; say(this: Person): void; } const person: Person = { name: 'captain', say() { console.log(this.name); }}; const fn = person.say; fn(); // ts(2684) The 'this' context of type 'void' is not assignable to method's 'this' of type 'Person'Copy the code
Note: Explicitly annotating functions with this, which ostensibly takes the place of the first parameter, doesn’t mean the function actually has an extra parameter because TypeScript translations to JavaScript erase the “pseudo-parameter” this. This is one of TypeScript’s few unique syntax features.
Function overloading
function convert(x: P2): string;
function convert(x: P1): number;
function convert(x: P1 | P2): any { }
const x1 = convert({ name: '' } as P1); // => number
const x2 = convert({ name: '', age: 18 } as P2); // => string
Copy the code
Type predicate (IS)
Return typeof s === 'string'; return typeof s === 'string'; } function isNumber(n: number) { return typeof n === 'number'; } function operator(x: Unknown) {if(isString(x)) {// ok x type is reduced to string} if(isNumber(x)) {// ts(2345) unknown cannot be assigned to number}}Copy the code
5. Class type
class
class Dog { name: string; constructor(name: string) { this.name = name; } bark() { console.log('Woof! Woof! '); } } const dog = new Dog('Q'); dog.bark(); // => 'Woof! Woof! 'Copy the code
inheritance
Using the extends keyword makes it easy to define an abstract schema for class inheritance
class Animal { type = 'Animal'; say(name: string) { console.log(`I'm ${name}! `); } } class Dog extends Animal { bark() { console.log('Woof! Woof! '); } } const dog = new Dog(); dog.bark(); // => 'Woof! Woof! ' dog.say('Q'); // => I'm Q! dog.type; // => AnimalCopy the code
Public, private, and protected modifiers
There are three access modifiers supported in TypeScript: public, private, and protected.
-
Public modifies properties or methods that are public and visible anywhere;
-
Private modifies properties or methods that are visible only in the same class and are private;
-
Protected modifies the properties or methods that are visible and protected only in the class itself and its subclasses.
Read-only modifier
Declare attributes of a class using the readonly read-only modifier
class Son {
public readonly firstName: string;
constructor(firstName: string) {
this.firstName = firstName;
}
}
const son = new Son('Tony');
son.firstName = 'Jack'; // ts(2540) Cannot assign to 'firstName' because it is a read-only property.
Copy the code
accessor
You can intercept read and write access to class members through getters and setters.
Static attributes
You can define static properties and methods for a class.
These properties exist on a particular object, the class, rather than an instance of the class, so we can access static properties directly from the class,
class MyArray {
static displayName = 'MyArray';
static isArray(obj: unknown) {
return Object.prototype.toString.call(obj).slice(8, -1) === 'Array';
}
}
console.log(MyArray.displayName); // => "MyArray"
console.log(MyArray.isArray([])); // => true
console.log(MyArray.isArray({})); // => false
Copy the code
Note that methods that do not rely on the instance this context can be defined as static methods, which means that you need to explicitly annotate this to use this in static methods; Non-static methods do not need to explicitly annotate this, because this points to an instance of the class by default.
An abstract class
A special class that cannot be instantiated and can only be inherited by subclasses.
abstract class Adder { abstract x: number; abstract y: number; abstract add(): number; displayName = 'Adder'; addTwice(): number { return (this.x + this.y) * 2; } } class NumAdder extends Adder { x: number; y: number; constructor(x: number, y: number) { super(); this.x = x; this.y = y; } add(): number { return this.x + this.y; } } const numAdder = new NumAdder(1, 2); console.log(numAdder.displayName); // => "Adder" console.log(numAdder.add()); // => 3 console.log(numAdder.addTwice()); / / = > 6Copy the code
The type of the class
The type of a class is similar to that of a function, that is, when a class is declared, it also declares a special type (specifically, an interface type). The name of the type is the class name, indicating the type of the class instance. When we define a class, we declare all property and method types other than constructors as members of this special type.
class A {
name: string;
constructor(name: string) {
this.name = name;
}
}
const a1: A = {}; // ts(2741) Property 'name' is missing in type '{}' but required in type 'A'.
const a2: A = { name: 'a2' }; // ok
Copy the code
6. Interface type and type alias
Interface Interface type
/** ProgramLanguage */ ProgramLanguage {/** ProgramLanguage */ name: string; /** age: () => number; }Copy the code
Defaultable property
/** OptionalProgramLanguage {/** OptionalProgramLanguage */ name: string; /** ** age? : () => number; } let OptionalTypeScript: OptionalProgramLanguage = { name: 'TypeScript' }; // okCopy the code
Read-only property
Interface ReadOnlyProgramLanguage {/** language name */ readonly name: string; Use fixed number of year / * * * / readonly age: (() = > number) | undefined; } let ReadOnlyTypeScript: ReadOnlyProgramLanguage = { name: 'TypeScript', age: } /** ts(2540) error, name only */ ReadOnlyTypeScript. Name = 'JavaScript';Copy the code
Defining function types
Interface StudyLanguage {(language: ProgramLanguage): void} /** StudyLanguage = language => console.log(`${language.name} ${language.age()}`);Copy the code
The index sign
interface LanguageRankInterface { [rank: number]: string; } interface LanguageYearInterface { [name: string]: number; } { let LanguageRankMap: LanguageRankInterface = { 1: 'TypeScript', // ok 2: 'JavaScript', // ok 'WrongINdex': '2012' // ts(2322) non-existent attribute name}; let LanguageMap: LanguageYearInterface = { TypeScript: 2012, // ok JavaScript: 1995, // ok 1: 1970 // ok }; }Copy the code
Note: In the example above, when a number is used as an object index, its type is compatible with both numbers and strings, which is consistent with JavaScript behavior. Therefore, when you index an object with 0 or ‘0’, the two are equivalent.
{ interface LanguageRankInterface { readonly [rank: number]: string; } interface LanguageYearInterface { readonly [name: string]: number; }} // LanguageRankInterface and LanguageYearInterface Any numeric or string attribute is read-only.Copy the code
Inheritance and Implementation
Interface inheritance can be implemented using the extends keyword as shown below.
{ interface DynamicLanguage extends ProgramLanguage { rank: number; } interface TypeSafeLanguage extends ProgramLanguage {typeChecker: string; } /** inherits multiple */ interface TypeScriptLanguage extends DynamicLanguage, TypeSafeLanguage {name: 'TypeScript'; // Redefine the property with compatible types of the original property type (such as subsets)}}Copy the code
Note: We can only override inherited properties with compatible types
{/** TS (6196) error inheritance, name attribute incompatible */ interface WrongTypeLanguage extends ProgramLanguage {name: number; }} // Because the name attribute of ProgramLanguage is string and the name attribute of WrongTypeLanguage is number, the two are incompatible, so they cannot be inherited and a TS (6196) error will be displayed.Copy the code
Type Type alias
/** Type alias */ {type LanguageType = {/** The following is the interface attribute */ /** language name */ name: string; /** age: () => number; }}Copy the code
For scenarios that cannot be covered by interface types, such as composite types and cross types, we can only receive them using type aliases
{/ * * * / type MixedType = string | number; /** intersecting */ type IntersectionType = {id: number; name: string; } & { age: number; name: string }; / / ProgramLanguage['age']; }Copy the code
Difference between Interface and Type
- Interface types are defined repeatedly, and their attributes are superimposed, which makes it extremely easy to extend global variables and third-party library types
{
interface Language {
id: number;
}
interface Language {
name: string;
}
let lang: Language = {
id: 1, // ok
name: 'name' // ok
}
}
Copy the code
- Defining the type alias repeatedly, as shown in the code below, prompts a TS (2300) error
{/** ts(2300) repeat flag */ type Language = {id: number; } /** ts(2300) repeated flag */ type Language = {name: string; } let lang: Language = { id: 1, name: 'name' } }Copy the code
7. Advanced types: union types and cross types
The joint type
The type of a variable or parameter is not a single atomic type, but may be a combination of different types.
Through “|” operator separate types of grammar to represent the joint type
function formatPX(size: number | string) { // ... } formatPX(13); // ok formatPX('13px'); // ok formatPX(true); / / ts (2345) 'true' type cannot give 'number | string' type formatPX (null); / / ts (2345) 'null' type cannot give 'number | string' typeCopy the code
We can combine any type and any type to construct a type that better meets our needs
function formatUnit(size: number | string, unit: 'px' | 'em' | 'rem' | '%' = 'px') {
// ...
}
formatUnit(1, 'em'); // ok
formatUnit('1px', 'rem'); // ok
formatUnit('1px', 'bem'); // ts(2345)
Copy the code
You can use a type alias to pull away from an upper union type and then join it further
type ModernUnit = 'vh' | 'vw'; type Unit = 'px' | 'em' | 'rem'; type MessedUp = ModernUnit | Unit; / / type is' the vh '|' vw '|' px '|' em '|' rem 'Copy the code
Interface types can be combined to represent more complex structures
interface Bird { fly(): void; layEggs(): void; } interface Fish { swim(): void; layEggs(): void; } const getPet: () => Bird | Fish = () => { return { // ... } as Bird | Fish; }; const Pet = getPet(); Pet.layEggs(); // ok Pet.fly(); // ts(2339) 'Fish' has no 'fly' attribute; 'Bird | Fish' not 'fly' attribute / / in joint type, we can direct access to each member has the interface properties, methods, and do not prompt type errors. However, if the attributes and methods are unique to individual members, we need to treat them differently. At this time, we need to introduce type guards to distinguish different member types.Copy the code
Type guards are required based on the IN operator
if (typeof Pet.fly === 'function') { // ts(2339)
Pet.fly(); // ts(2339)
}
if ('fly' in Pet) {
Pet.fly(); // ok
}
Copy the code
Cross type
To combine multiple types into a single type, the combined type has the characteristics of all member types
Merging interface types
The real use of federated interface types is to combine multiple interface types into one type to achieve the same effect as interface inheritance, known as merged interface types
type IntersectionType = { id: number; name: string; }
& { age: number };
const mixed: IntersectionType = {
id: 1,
name: 'name',
age: 18
}
Copy the code
If the name attribute type is incompatible, such as in the example above where the name attribute type of the two interface types is number and string, the name attribute type is the intersection of the atomic types number and string, that is, never
type IntersectionTypeConfict = { id: number; name: string; } & { age: number; name: number; }; Const mixedConflict: IntersectionTypeConfict = {id: 1, name: 2, // ts(2322) error, 'number' cannot be assigned to 'never' age: 2};Copy the code
If an attribute of the same name has a compatible type, such as number, a subtype of number, or a numeric literal type, then the merged name attribute is a subtype of either.
type IntersectionTypeConfict = { id: number; name: 2; } & { age: number; name: number; }; let mixedConflict: IntersectionTypeConfict = { id: 1, name: 2, // ok age: 2 }; MixedConflict = {id: 1, name: 22, // '22' cannot be assigned to '2' age: 2};Copy the code
Merge union type
You can merge a union type into a cross type that satisfies the different union type constraints, that is, the members of the same type that are extracted from all union types. Here, we can also think of merging union types as finding an intersection.
type UnionA = 'px' | 'em' | 'rem' | '%';
type UnionB = 'vh' | 'em' | 'rem' | 'pt';
type IntersectionUnion = UnionA & UnionB;
const intersectionA: IntersectionUnion = 'em'; // ok
const intersectionB: IntersectionUnion = 'rem'; // ok
const intersectionC: IntersectionUnion = 'px'; // ts(2322)
const intersectionD: IntersectionUnion = 'pt'; // ts(2322)
Copy the code
Union, cross combination
Joint operator | priority & below the cross operator, also, we can through the use of the small bracket () to adjust the priority of the operators.
type UnionIntersectionA = { id: number; } & { name: string; } | { id: string; } & { name: number; }; / / crossover operator precedence above joint operators type UnionIntersectionB = (' px '|' em '|' rem '|' % ') | (' the vh '|' em '|' rem '|' pt); // Adjust the priorityCopy the code
Furthermore, we can also introduce basic rules such as distributive ratio and commutative law into type combinations and then optimize for cleaner and cleaner types,
type UnionIntersectionC = ({ id: number; } & { name: string; } | { id: string; }) & { name: number; }; type UnionIntersectionD = { id: number; } & { name: string; } & { name: number; } | { id: string; } & { name: number; }; Type UnionIntersectionE = ({id: string; } | { id: number; } & { name: string; }) & { name: number; }; // It satisfies the commutative lawCopy the code
Type of cut
What is the effect of combining a string primitive type with a string literal type into a joint type? The effect is that the type is reduced to string
type URStr = 'string' | string; / / type is string type URNum = 2 | number; / / type is number type URBoolen = true | Boolean; / / type is a Boolean enum EnumUR {ONE, TWO} type URE = EnumUR. ONE | EnumUR; // The type is EnumURCopy the code
Reduced, but greatly reduced the ability of the IDE to autoprompt,
type BorderColor = 'black' | 'red' | 'green' | 'yellow' | 'blue' | string; In the code above, we wanted the IDE to automatically prompt for annotated string literals, but since the type was reduced to string, all string literals black, red, and so on were not automatically prompt. TypeScript also provides a dark magic that allows type reduction to be controlled. As shown in the following code, we only need to add to the parent type "&" {} can type BorderColor = 'black' | 'red' | 'green' | 'yellow' | 'blue' | string & {}; // All literal types are preservedCopy the code
8. Enumeration types
Enumerated type
enum Day {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
Copy the code
There are seven common enumeration types:
Numeric types, string types, heterogeneous types, constant and computed (value) members, enumerator and joint enumerations, constant enumerations, external enumerations.
- Numeric enumerations: By specifying only constant names, we define a set of numbers that starts incrementing from 0 by default, called numeric enumerations. If we want the enumeration value to increment from another value, we can display the initial value of the specified enumeration member in the format “constant name = value”
enum Day {
SUNDAY = 1,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
Copy the code
Assign SUNDAY to any type (such as integer, negative, decimal, etc.), starting with any number, and incrementing members that do not display the specified value by 1
- String enumerations: Enumerations that define values as string literals are called string enumerations, and string enumerations retain those values after being translated into JavaScript
enum Day {
SUNDAY = 'SUNDAY',
MONDAY = 'MONDAY',
...
}
Copy the code
-
Heterogeneous enums: TypeScript supports enumeration types that have both numeric and character members. Such enumerations are called Heterogeneous enums.
-
Constant and computed (value) members: In the previous example, the enumerated members involved, whose values are strings, numeric literals, and numeric constants incrementing from 0 with an unspecified initial value, are referred to as constant members. In translation, members that define values through evaluated constant enumeration expressions are also called constant members, as in the following cases:
-
References come from a predefined constant member, such as from the current enumeration or another enumeration;
-
Constant enumeration expression wrapped in parentheses ();
-
The unary operators +, -, ~ applied to constant enumeration expressions;
-
Constant enumeration operation expression of binary operators +, -, *, /, %, < <, > >, > > >, &, |, ^.
Except in these cases, all others are considered calculated members.
Enum FileAccess {/ / constant member None, Read = 1 < < 1, the Write = 1 < < 2, ReadWrite = Read | Write, / / calculated members G = "123". The length,}Copy the code
-
-
Enumeration member types and union enumerations
The relationship between an enumeration member and an enumeration type can be described in two ways: if the enumeration member contains both literal and non-literal enumeration values, the type of the enumeration member is the enumeration itself (the enumeration type is itself a subtype); If enumerators are all literal enumerations, then all enumerators are both values and types
enum Day { SUNDAY, MONDAY, } enum MyDay { SUNDAY, MONDAY = Day.MONDAY } const mondayIsDay: Day.MONDAY = Day.MONDAY; // ok: the literal enumerator is both a value and a type const mondayIsSunday = myday.sunday; // ok: the type is MyDay, myday. SUNDAY is just the value const mondayIsMyDay2: myday. MONDAY = myday. MONDAY; // ts(2535), MyDay contains non-literal-valued members, so myday.monday cannot be used as a typeCopy the code
-
Constant enumeration (const enums)
const enum Day { SUNDAY, MONDAY } const work = (d: Day) => { switch (d) { case Day.SUNDAY: return 'take a rest'; case Day.MONDAY: return 'work hard'; }}Copy the code
-
External enumeration (Ambient enums) : Describes a variable that has been defined elsewhere by declare
declare let $: any; $('#id').addClass('show'); // ok Copy the code
-
The differences between external enumerations and regular enumerations are the following:
-
In an external enumeration, members that do not specify an initial value are treated as calculated (value) members, as opposed to regular enumerations.
-
Even if an external enumeration contains only literal members, those members are not of a literal member type, and naturally do not have all the features of a literal type.
-
9. The generic
Generics refer to type parameterization, that is, parameterization of a specific type. As with function parameters, we can define several type parameters for a generic type and pass them explicit type parameters when called. Generics are designed to effectively constrain the relationships between type members, such as function parameters and return values, or between class or interface members and methods.
Generic type parameters
function reflect<P>(param: P) {
return param;
}
Copy the code
Generics can not only restrict the type of the whole parameter of a function, but also restrict the type of the parameter properties and members. For example, the type of the parameter can be array, object
function reflectArray<P>(param: P[]) {
return param;
}
const reflectArr = reflectArray([1, '1']); // reflectArr 是 (string | number)[]
Copy the code
A generic class
In class definitions, we can also use generics to constrain the types of constructors, properties, and methods
class Memory<S> { store: S; constructor(store: S) { this.store = store; } set(store: S) { this.store = store; } get() { return this.store; } } const numMemory = new Memory<number>(1); // <number> default const getNumMemory = nummemory.get (); // The type is number nummemory.set (2); // Can only write number const strMemory = new Memory(" "); // Default <string> const getStrMemory = strmemory.get (); // The type is string strmemory.set ('string'); // Only string can be writtenCopy the code
The generic type
const reflectFn: <P>(param: P) => P = reflect; // ok
Copy the code
type ReflectFuncton = <P>(param: P) => P;
interface IReflectFuncton {
<P>(param: P): P
}
const reflectFn2: ReflectFuncton = reflect;
const reflectFn3: IReflectFuncton = reflect;
Copy the code
Note: Enumeration types do not support generics.
Generic constraint
Restrict generic input parameters to a relatively unambiguous set to constrain the input parameters.
function reflectSpecified<P extends number | string | boolean>(param: P):P { return param; } reflectSpecified('string'); // ok reflectSpecified(1); // ok reflectSpecified(true); // ok reflectSpecified(null); / / ts (2345) 'null' not give type 'number | string | Boolean'Copy the code