TS and JS
ts | js | |
---|---|---|
Function return value | Have a type | There is no |
Function parameters | Mandatory and optional parameters | All parameters are optional |
Function overloading | There are | There is no |
typeof | Deduce the type of a variable | Gets the type of the variable |
extends | Type extension in interface, Boolean operation in conditional type statements, restriction in generics, inheritance in class | Inheritance is represented in class |
window | A = {}, (window as any). A = {}; correct | Window. a = {} That’s right |
Basic foundation
The type of ts
Object represents a non-primitive type, that is, a type other than number, string, Boolean, symbol, NULL, or undefined.
In addition to the JS type, Tuple enum Any void Never unknown is also available
The value is a string array. Double quotation marks are recommended
Tuple
The primitive type is a kind of array, can specify a variety of types, personally feel more powerful than array
Void
function voidFun(): void {
console.log("hello");
}
voidFun() //hello
Copy the code
Note: It is useless to declare a variable of type void because its value can only be undefined or null
let unusable: void = undefined; let unusable1: void ; console.log(unusable); //undefined console.log(unusable1); //undefined let unusable: void = null; // Unusable prompt: type 'null' is not assignable to type 'void'Copy the code
Null, and Undefined
By default null and undefined are subtypes of all types. However, if strictNullChecks is specified, null and undefined can only be assigned to void and their respective types.
let a: undefined = undefined;
let b: null = null;
Copy the code
Never
- The never type represents the type of values that never exist. For example, the never type is the return type of function expressions or arrow function expressions that always throw an exception or have no return value at all.
- A function that returns never must have an unreachable end
- Use never to avoid new union types that have no corresponding implementation,
The goal is to write type-safe code
.
type Foo = string | number;
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// here foo is narrowed to string
} else if (typeof foo === "number") {
// here foo is narrowed to number
} else {
// foo is never
const check: never= foo; }} insteadtype Foo = string | number | boolean;
Copy the code
ControlFlowAnalysisWithNever else branch foo type can be narrowed to a Boolean type, lead to cannot be assigned to never type, then will generate a compiler error. Make sure your code is absolutely secure.
null undefined never
var a:number
console.log(a) StrictNullChecks -strictNullChecksDefined but not assigned isundefined
var a:number|undefined
console.log(a) //undefined
nullIn the same wayCopy the code
There is no –strictNullChecks flag, null and undefined can be assigned to any type. Null and undefined are valid values for all other types
Enumeration (enum) : supports the sum of numbers and strings
Enumeration types are definition identifiers that define fixed values.
Usually the first letter is capitalized
- Digital enumeration
- If no value is assigned, the default value is the index value. Note that the index value starts at 0
- The remaining members grow automatically from the initialized value
- The first element starts at 0 before it has an initialization value
For example, pay_status 0 does not pay 1 pays 2 transactions successfully
enum Flag {success=1, error=0}
var f:Flag = Flag.success
console.log(f) / / 1
enum Color{red,blue,green}
var c:Color = Color.red
console.log(c) / / 0If no value is assigned, the default value is the index value. Note that the index value is0Start enum Color {red, blue =5,green}
var c:Color = Color.red
var c1:Color = Color.blue
var c2:Color = Color.green
console.log(c,c1,c2) / / 0 5 6Green does not have a value as the previous benchmarkCopy the code
- String enumeration: more readable than numeric enumeration
In string enumerations, each member must be initialized with either a string literal or another string enumerator.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",}Copy the code
- Heterogeneous enumeration: It is possible to mix number and string, but this is not generally used
enum Test {
No = 0,
Yes = "YES",}Copy the code
Sometimes type, sometimes value
Said value:
enum Pos {
LEFT,
RIGHT
}
let p : Pos = Pos.RIGHT
console.log(p) / / 1
enum Pos {
LEFT = 5,
RIGHT
}
let p : Pos = Pos.RIGHT
console.log(p) / / 6
enum Pos {
LEFT = '1',
RIGHT = '2'
}
let p : Pos = Pos.RIGHT
console.log(p) / / '2'
enum Pos {
A,
B,
LEFT = '1',
RIGHT = '2',}let p : Pos = Pos.RIGHT
console.log(p) / / '2'
console.log(Pos[0]) // 'A'
Copy the code
According to the type
enum ActiveType {
Active,
Inactive
}
type KeyOfType = keyof typeof ActiveType // "Active" | "Inactive"
let test: KeyOfType = 'Active' || 'Inactive' //ok
Copy the code
High-level types
- Crossover type: Combines multiple types into a single type
We mostly see the use of cross types in mixins or other places that don’t fit into a typical object-oriented model. (There are plenty of occasions when this happens in JavaScript!)
Person & Serializable & Loggable
Copy the code
- The joint type
padding: string | number
Copy the code
www.tslang.cn/docs/handbo…
- Type protection and type differentiation
Is: This keyword is used as user type protection to tell TS how to identify the type
interface Animal {
walk: () = >{}}// cat is Animal
function isAnimal(cat: any) :cat is Animal {
return (cat asAnimal).walk ! = =undefined;
}
let cat = {}
if (isAnimal(cat)) {
cat.walk() // OK
} else {
pet.walk() // There is no property "swim" on type "Bird"
}
Copy the code
Other keywords you can use to determine types are typeof, instanceof, in, and so on.
typeOf
Typeof type protection * Only two forms can be recognized: typeof V === “typename” and typeof V! “Typename”, “typename” must be “number”, “string”, “Boolean” or “symbol”. But TypeScript doesn’t prevent you from comparing with other strings, and the language doesn’t recognize those expressions as type-protected.
function padLeft(value: string, padding: string | number) {
// There is no need to define a function to determine whether a type is primitive
if (typeof padding === "number") {
return Array(padding + 1).join("") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'. `);
}
Copy the code
- instanceof
Instanceof type protection is a way to refine types through constructors. The right side of Instanceof requires a constructor, which TypeScript refines to:
The type of the prototype property of this constructor, if its type is not any, constructs the union of the types returned by the signature
Optional parameters and optional properties:It must be optional, which is the belt, right?
Use – strictNullChecks, optional parameters will be automatically add | is undefined
function f(x: number, y? : number) {
return x + (y || 0);
}
f(1.2);
f(1);
f(1.undefined);
f(1.null); // error, 'null' is not assignable to 'number | undefined'
Copy the code
The same is true for optional attributes:
class C {
a: number; b? : number; }let c = new C();
c.a = 12;
c.a = undefined; // error, 'undefined' is not assignable to 'number'
c.b = 13;
c.b = undefined; // ok
c.b = null; // error, 'null' is not assignable to 'number | undefined'
Copy the code
Manually remove null or undefined using type assertions, syntax is add! The suffix
identifier! Removed from the identifier typenullandundefined
Copy the code
Type alias type: gives a type a new name
-
Type aliases are sometimes similar to interfaces, but can work with primitive values, union types, tuples, and any other type you need to write by hand.
-
Type aliases can also be generic – we can add type parameters and pass them to the right of the alias declaration
type Container<T> = { value: T };
Copy the code
- You can use type aliases in attributes
Refer to your
type Tree<T> = {
value: T;
left: Tree<T>;
right: Tree<T>;
}
Copy the code
Note: Type aliases cannot appear anywhere on the right side of declarations
type Yikes = Array<Yikes>; // error
Copy the code
The difference between interface and type alias type
Interface creates a new name
Can be used anywhere else.Type does not create a new name
For example, error messages do not use aliases.
type Alias = { num: number }
interface Interface {
num: number;
}
declare function aliased(arg: Alias) :Alias;
declare function interfaced(arg: Interface) :Interface; Hovering over interfaced in the compiler returns Interface over Aliased, but displays object literal typesCopy the code
Type cannot be extends or implements
(You cannot extends and implements other types yourself).
Because objects in software should be open to extension but closed to modification, you should try to use interfaces instead of type aliases.
- If you cannot describe a type by interface and need to use a union or tuple type, type is usually used.
Summary describes various types of ways:
- interface
- The joint type
- Cross type
- tuples
- type
The new type typeof Tuple object can be obtained in a number of ways
Interface types can be combined
The index type query operator keyof
Usage: keyof T
Index access operator T[K]
function getProperty<T.K extends keyof T> (o: T, name: K) :T[K] {
return o[name]; // o[name] is of type T[K]
}
Copy the code
type Teacher = {
id: string;
name: string;
};
type TeacherKeys = keyof Teacher; //"id" | "name"
let a: TeacherKeys = 'id' || 'name' // ok
let a: TeacherKeys = 'other' //error
Copy the code
Keyof and T[K] are used in conjunction with the string index signature. Keyof T will be string and T[string] will be the type of the index signature:
interface Map<T> {
[key: string]: T;
}
let keys: keyof Map<number>; // string
let value: Map<number>['foo']; // number
Copy the code
Keyof can do mapping type, specific can see website www.tslang.cn/docs/handbo…
Keyof Typeof is used in combination
enum ActiveType {
Active,
Inactive
}
type KeyOfType = keyof typeof ActiveType // "Active" | "Inactive"
Copy the code
To obtain the key typeof an enum, use typeof and then keyof as the value.
enum ActiveType {
Active,
Inactive
}
type KeyOfType = keyof ActiveType // "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"
let test : KeyOfType = 'toString'
console.log(test) //'toString'
Copy the code
Type assertion can be done in two ways
-
- Angle brackets
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
Copy the code
-
- As grammar
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
Copy the code
The two forms are equivalent. Which to use is mostly a matter of personal preference; However, when you use JSX in TypeScript, only AS syntax assertions are allowed.
interface
The role of interface, in object-oriented programming, interface is a standard definition, play a role of restriction and specification.
The batch method can be constrained www.tslang.cn/docs/handbo… One of the benefits of optional attributes is that you can pre-define possible attributes, and another is that you can catch errors when references to non-existent attributes.
It is also not possible to assign the entire ReadonlyArray to a normal array
let a: number[] = [1.2.3.4];
let ro: ReadonlyArray<number> = a;
a = ro; // error!
Copy the code
readonly vs const
The easiest way to determine whether to use readonly or const is to use it as a variable or as a property. Const as a variable, readonly as an attribute
- Additional property checking
Ways to get around definition errors:
- assertions
- The index sign
- Assign this object to one variable and another
Problems type assertions can bypass:
- Indexable types (constraints that can be placed on objects and arrays)
TS supports two index signatures: string and number. Both types of indexes can be used, but the return value of the numeric index must be a subtype of the return value type of the string index. This is because when you index a number, JavaScript converts it to a string and then indexes the object. That is, indexing with 100 (a number) is the same as indexing with 100 (a string), so the two need to be consistent.
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// Error: Use numeric string index, sometimes get completely different Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
Copy the code
String index signatures do a good job of describing dictionary patterns, and they also ensure that all attributes match their return value types.
interface NumberDictionary {
[index: string]: number;
length: number; // Yes, length is number
name: string // Error, the type of 'name' does not match the type of the index type returned value
}
Copy the code
You can set the index signature to read-only
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice"."Bob"];
myArray[2] = "Mallory"; // error!
Copy the code
- Interface Inheritance interface
An interface can inherit multiple interfaces to create a composite interface of multiple interfaces. interface Shape {color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Copy the code
- Mixed type
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter() :Counter {}
Copy the code
- Interface inheritance class
When an interface inherits a class type, it inherits the members of the class but not its implementation. It is as if an interface declares all the members of a class, but does not provide an implementation. Interfaces also inherit to the private and protected members of the class.
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select(){}}class TextBox extends Control {
select(){}}// Error: The "Image" type is missing the "state" attribute.
class Image implements SelectableControl {
select(){}}class Location {}Copy the code
class
www.tslang.cn/docs/handbo… Override the method of the parent class
Protected methods; You can’t use name outside of the Person class, but you can still access it through an instance method of the Employee class because Employee is derived from Person.
Abstract methods in abstract classes contain no concrete implementation and must be implemented in derived classes
. The syntax of abstract methods is similar to that of interface methods. Both define the method signature but do not contain the method body. However, abstract methods must contain the abstract keyword and can contain access modifiers.
If there are abstract methods, there must be abstract classes. Subclasses of an abstract class must implement the abstract methods in the abstract class.
- Use classes as interfaces
Why static methods? You don’t usually use static methods to call instance properties directly from a class. You can call static properties in a class directly.
Note: Class type interfaces: The constraints on classes are somewhat similar to those on abstract classes
function
- Optional and default parameters
Optional arguments must be followed by required arguments
Unlike normal optional parameters, parameters with default values do not need to be placed after required parameters. If a parameter with a default value appears before a mandatory parameter, the user must explicitly pass undefined to get the default value.
function buildName(firstName = "Will", 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"); // okay and returns "Bob Adams"
let result4 = buildName(undefined."Adams"); // okay and returns "Will Adams"
Copy the code
- The remaining parameters
The remaining parameters are treated as an unlimited number of optional parameters. You could have none, you could have any of them.
- Arrow function
class Handler {
info: string;
onClickGood = (e: Event) = > { this.info = e.message }
}
Copy the code
- Function overloading
When defining overloads, always put the most precise definition first
Generic (type variable T)
Generics address the reuse of class interface methods, support for indeterminous data types, and type validation. Any does not have type verification.
Type: generic classes generic functions Generic interfaces
-
A generic is a function that uses T as a type variable
-
Why use generics and not any?
No loss of information.
Using any causes the function to accept arG arguments of any type, and some information is lost: the type passed in should be the same as the type returned. If we pass in a number, we just know that any type of value can be returned. Therefore, we need a way to make the type of the return value the same as the type of the parameter passed in. That is, using generics (type variables, used only to represent types, not values)
function identity<T> (arg: T) :T {
return arg;
}
Copy the code
- After a generic function, you can use it in two ways:
- Pass all arguments, including type arguments:
let output = identity<string>("myString"); // type of output will be 'string'
Copy the code
Explicitly specifies that T is a string and is passed to the function as an argument, enclosed in <> instead of ().
The more general
. We take advantage of type corollaries — that is, the compiler automatically helps us determine the type of T based on the parameters passed in
let output = identity("myString"); // type of output will be 'string'
Copy the code
Type inference helps us keep our code lean and readable. If the compiler cannot automatically infer the type, it can only pass in the type of T explicitly as above, which is possible in some complicated cases.
This parameter is optional. Generic application Scenarios When to use index signature This parameter is optional
-
Use generic variables
-
The generic type
-
A generic class
A class has two parts: a static part and an instance part. A generic class refers to the type of the instance part, so static attributes of the class cannot use this generic type.
- Generic constraint
Extends uses type parameters in generic constraints and class types in generics
- A generic interface
Writing a:
interface Config{
<T>(value:T):T
}
var getData:Config=function<T> (The value; T) :T{
return value
}
getData<string>('Joe')
Copy the code
Method 2:
interface Config<T>{
(value:T):T
}
function getData<T> (The value; T) :T{
return value
}
var myGeData:Config<string> = getData
myGeData('Joe')
Copy the code
- Generic classes that take classes as parameter types
- Define the class
- Classes are used as parameters to constrain the type of data passed in
Example: Define a User class that maps database fields, define a MysqlDb class that operates on the database, and pass the User class into MysqlDb as a parameter
Each time you manipulate a table, you have to re-pass the data type, so it’s best to use generics and duplicate the code
A generic class// The generic class that operates on the database
class MysqlDb<T>{
add(info:T):boolean{
console.log(info)
return true
}
update(info:T,id:number):boolean{}
}
// Define a User class and database mapping
class user{
username:string|undefined
}
var u = new User()
u.username='Joe'
class user1{
username:string|undefined
}
var u1 = new User1()
u1.username='Joe'
var db = newMysqlDb<User>() db.add(u) db.add(u1)... MysqlDb<User>() db.add(u) db.add(u1)... You can add multipleCopy the code
The namespace
Mainly used to organize code and avoid naming conflicts
namespace A{
class Dog{}}let g = new A.Dog()
Copy the code
Differences between namespaces and modules
Namespaces: mainly used to organize code, avoid naming conflicts module: focus on code reuse, a module may have more than one namespace.
The index sign
Attributes can be dynamically assigned to objects (string key names and any type of key value) using “index signature”, similar to let obj = {},obj. Name = ‘hannie’ in JS.
interface LooseObj {
[key: string] :any
}
let developer: LooseObj = {};
developer.name = "hannie";
Copy the code
Index signatures can be used to define the types of properties and values in an object. For example, to define a React component, this allows Props to pass any Props whose key is string and value is number.
interface Props {
[key: string] :number
}
<Component count={1} / >// OK
<Component count={true} /> // Error
<Component count={'1'} / > // Error
Copy the code
How do I dynamically assign attributes to objects
-
- The index sign
interface LooseObj {
[key: string] :any
}
let developer: LooseObj = {};
developer.name = "hannie";
Copy the code
-
- Define optional attributes
interface Developer {
name: string; age? :number;
[key: string] :any
}
let developer: Developer = { name: "hannie" };
developer.age = 18;
developer.city = "beijing";
Copy the code
-
- Record
,valuestype>
: Defines the type of the object whose key type is keysType and value type is valuesType
- Record
interface Developer extends Record<string, any> {
name: string; age? :number;
}
let developer: Developer = { name: "hannie" };
developer.age = 18;
developer.city = "beijing";
Copy the code
Type V<T> = T type NumberValue = V<number> var a:NumberValue = 1 console.log(a) Index signature type Test = {foo: number; Bar: string} type N = Test['foo'] // number // Type IsNumber<T> = T extends Number? number : string; type A = IsNumber<2> // yes type B = IsNumber<'3'> // no let b:B = '2' console.log(b) type TypeName<T> = T extends string ? "string" : T extends boolean ? "boolean" : "object"; type T0 = TypeName<string>; // "string" type T1 = TypeName<"a">; // "string" type T2 = TypeName<true>; // "boolean"Copy the code
type Value<T> = T type NumberValue = Value<number> type V<T> = T type NumberValue1 = V<number> type Test = { foo: number; Bar: string} type N = Test['foo'] // number // var a:NumberValue = 1 console.log(a) type IsNumber<T> = T extends number ? number : string; type A = IsNumber<2> // yes type B = IsNumber<'3'> // no let b:B = '2' console.log(b) type TypeName<T> = T extends string ? "string" : T extends boolean ? "boolean" : "object"; type T0 = TypeName<string>; // "string" type T1 = TypeName<"a">; // "string" type T2 = TypeName<true>; // "boolean"Copy the code
Other details
readonly vs const
The easiest way to determine whether to use readonly or const is to use it as a variable or as a property. Const as a variable, readonly as an attribute.
Const usage scenario: If a variable doesn’t need to be written to, then anyone else using the code can’t write to it either
There are other unexpected limitations to object expansion. First, it contains only enumerable properties of the object itself. Basically, when you expand an object instance, you lose its methods
class C { p = 12; m() { } } let c = new C(); let clone = { ... c }; clone.p; // ok clone.m(); // error!Copy the code
{}|object|Object
The Object interface defines properties on the Object.prototype prototype Object
const proto = {};
Object.create(proto); // OK
Object.create(null); // OK
Object.create(undefined); // // Object prototype may only be an Object or null: undefined
Object.create(11); // Object prototype may only be an Object or null: 11
Object.create(true); // Error
Object.create("oops"); // Error
Copy the code
Object represents a normal Javascript object type, not an underlying data type.
declare function create(o: object): void; create({ prop: 0 }); // OK create(null); // Error create(undefined); // Error create(42); // Error create("string"); // Error create(false); // Error create({ toString() { return 3; }}); // OKCopy the code
Error, can only be created for objects
{} represents any type of non-null, non-undefined.
interface User {
id: string
}
interface User {
name: string
}
interface User {
other: object
}
const user = {} as User
console.log(user.id);
console.log(user.name);
console.log(user.other);
user.other = {a:1}
Copy the code
Interface User {other: {}} user.other = null ErrorCopy the code
Interface User {other: Object} const User = {} as User user.other = {toString(){return 1}} // errorCopy the code
type User2 = string
let a = '' as User2
a = '2'
let isDone: boolean = false;
var a : string = '1'
let b : number = 1
Copy the code
conclusion
Generics can be used to create reusable components that can support multiple types of data. This allows users to use components with their own data types
Summing up this arrow function instance can override the result
When JSX is used in TypeScript, only AS syntax assertions are allowed.
Use let instead of var whenever possible
Typescript.bootcss.com/functions.h…
Type type
Type typing allows Typescript to use types as objects take property values
type Teacher = {
id: string
sthdentList: {
fristName: string
lastName: string
}[]
}
type UserIdType = Teacher['id'] // string
type SthdentList = Teacher['sthdentList'] // { fristName: string; lastName: string; }[]
type Friend = SthdentList[number] // { fristName: string; lastName: string; }
Copy the code
UserIdType, SthdentList, and Friend are the resulting new types
type Tuple = [number, string]
type First = Tuple[0] // number
type Second = Tuple[1] // string
Copy the code
It can also be used for primitives
conclusion
Consider using generics when the type is uncertain
Common generics used in everyday development include Promise, Array, react.component.etc.
As with generics, you don’t need decorators for small projects, but you should be able to read someone else’s frame.
Any does away with type detection. Generics can restrict what types are passed in and returned, but they can support unspecified data types.
In the development process, you can try to use the keyof enum Tuple type to determine the type of interface function class, generic type to be able to understand
Juejin. Cn/post / 687698…
Juejin. Cn/post / 687175…