● In the previous chapter, we talked about the interface of TS
● In this chapter, we will talk about TS enumerations and constraints
enumerate
Recognize enumerations
● The concept of enums is found in many computer languages, but there is no such concept in JS, and to compensate for this shortcoming, enumeration types are added to TS
● What is an enumeration?
Enumeration ( mei ju ): Enumeration means to list one by one, list all cases, then when taking the value, only these few can be used, and the others are not available
Enumerations in computer languages: Put all constants in a set so that several constants become a set of related content
// 针对一个业务逻辑, 我需要频繁用到四个方向的字符串
const UP = 'up'
const RIGHT = 'right'
const DOWN = 'down'
const LEFT = 'left'
● For the above four variables
● I don't care about any logic, I can't limit you to using only one of these four variables
// 封装一个功能函数
function util(dir) {}
● No matter what method you use, you can't limit the dir parameter to the four directions listed above
● At this point, we can use the enumeration
● First, in TS, create an enumeration set with the enum keyword and put the four constants we need into it
enum Direction {
UP = 'up',
RIGHT = 'right',
DOWN = 'down',
LEFT = 'left'
}
Make a DIrection enumeration collection, which can be used to restrict certain data
function util(dir: Direction) {}
● It is agreed that the value of the dir parameter can only be a constant in the enumeration collection of Direction, and nothing else
● As long as you don't write the contents of the Direction enumeration, you can't do it
Numeric enumeration
● Numeric enumeration : Every constant in an enumeration type is a number
● In TS, every constant in an enumeration, when you do not set a value, defaults to the number type
enum Pages {
ONE, // 0
TWO, // 1
THREE // 2
}
● Your constants in the enumeration, the first default value is 0, followed by +1 increments
At this time
Pages.ONE => 0
Pages.TWO => 1
Pages.THREE => 2
● We can also specify the value ourselves
enum Pages {
ONE = 10, // 10
TWO = 20, // 20
THREE = 30 // 30
}
● At this time, the constants in the enumeration set are the values we specify
● We can also specify partial values
enum Pages {
ONE = 10, // 10
TWO, // 11
THREE // 12
}
● The unspecified constant after the specified constant will be incremented once according to the rule of +1
enum Pages {
ONE, // 0
TWO = 10, // 10
THREE // 11
}
enum Pages {
ONE, // 0
TWO = 10, // 10
THREE, // 11
FOUR = 30, // 30
FIVE // 31
}
String enumeration
● String enumeration: The value of each constant in the enumeration collection is of type string
● In TS, you must specify a value for the string type to appear
enum Direction {
UP = 'up',
RIGHT = 'right',
DOWN = 'down',
LEFT = 'left'
}
● In TS, enumeration constants are not the same as anything, including raw strings
function util(dir: Direction) {}
● This is because, in TS, each constant within an enumeration is a unique value
● So when you use an enumeration to qualify a piece of data, you can only use the values in the enumeration
● This also avoids word mistakes that you make due to hand mistakes, such as whether you think 'form' and 'from' are the same word
Heterogeneous enumeration
● Heterogeneous enumeration: In fact, it is a mixture of numeric enumeration and string enumeration in an enumeration collection
But you probably won't use it that way, because we, as a collection of data, don't usually mix numbers and strings
enum Info {
ONE,
UP = 'up',
TWO = 2,
LEFT = 'left'
}
● There is a point to note here
Because in the enumeration collection, when you do not set a value for a certain key, it will default to the previous value +1
So if the previous one is a string enumeration, then the next one must be assigned manually, otherwise an error will be reported
If the previous one is a numeric enumeration, then the next one can be assigned manually without the need and will be calculated according to the previous +1
Enumeration merges
● Enumerations within TS, which support merging
● Multiple enumeration types can be written separately and will be automatically merged at compile time
enum Direction {
UP = 'up',
RIGHT = 'right',
DOWN = 'down',
LEFT = 'left'
}
enum Direction {
TOP = 'top',
BOTTOM = 'bottom'
}
function util(dir: Direction) {}
util(Direction.BOTTOM)
util(Direction.LEFT)
● The two enums defined here are called Direction, which will be automatically put together at compile time without conflict
Reverse mapping
● The number enumeration in TS will compile the key and value upside down at the same time when compiling
enum Pages {
ONE, // 0
TWO, // 1
THREE // 2
}
● Using this as an example, how does he compile it
var Pages;
(function (Pages) {
Pages[Enum["ONE"] = 0] = "ONE"
Pages[Enum["TWO"] = 1] = "TWO"
Pages[Enum["THREE"] = 2] = "THREE"
})(Pages || (Pages = {}));
● The result of the compilation
Pages = {
ONE: 0,
TWO: 1,
THREE: 2,
'0': 'ONE',
'1': 'TWO',
'2': 'THREE'
}
● That is, when we use it inside TS, if it is a numeric enumeration
● Then we can get the corresponding number through the key, or we can get the corresponding key through the corresponding number
enum Pages {
ONE, // 0
TWO, // 1
THREE // 2
}
console.log(Pages.ONE) // 0
console.log(Pages.TWO) // 1
console.log(Pages.THREE) // 2
console.log(Pages[0]) // 'ONE'
console.log(Pages[1]) // 'TWO'
console.log(Pages[2]) // 'THREE'
Constant enumeration
● Constant enumeration, which is modified by adding the const keyword to the enumeration
● When compiling, the enumeration content will be deleted, and only the compilation result will be retained
● And for numeric enumerations, the reverse mapping capability is not supported, and can only be accessed using keys
● Non-constant enumeration
enum Pages {
ONE, // 0
TWO, // 1
THREE // 2
}
console.log(Pages.ONE)
console.log(Pages.TWO)
console.log(Pages.THREE)
○ Compiled js file
● Constant enumeration
const enum Pages {
ONE, // 0
TWO, // 1
THREE // 2
}
console.log(Pages.ONE)
console.log(Pages.TWO)
console.log(Pages.THREE)
○ Compiled js file
Type constraints
● In TS, there is also a very magical keyword called type
● Type is also called type alias has many magical features, not only supports interface-defined object structures, but also supports any handwriting type
● Let's start with a very simple example
let n1: number | string | boolean
let n2: number | string | boolean
let n3: number | string | boolean
● Looking at the above code, we define three variables: n1 and n2 and n3
○ The restrictions on types are number or string or boolean
● It is very troublesome to write
● At this time, we can use type to alias it
type Info = number | string | boolean
let n1: Info
let n2: Info
let n3: Info
● In this way, our code has become concise
● Maybe friends think that this is not used much, but type is not the only function
Common use of type
● Basic type of alias
type n = number
let num: n = 100
○ This is a very basic use, giving the type number an alias called n
○ In the future, when using n to restrict variables, you are actually using number
● Basic type union
type i = number | string
let str: i = '千锋大前端'
str = 100
○ This is the union type, and the number or string type has an alias called i
○ When we use i to restrict a variable, the variable is restricted to number or string
● Object type
type User = { name: string, age: number }
let person: User = { name: '千锋大前端', age: 10 }
○ This is the object type, much like interface, and the usefulness is basically the same
● Object federation type
type User = { name: string, age: number }
type Person = User & { gender: boolean }
let person: Person = { name: '千锋大前端', age: 10, gender: true }
○ This is the object union type, much like the extends inheritance of interface
Tuple type
type data = [ number, string ]
let info: data = [ 10, '千锋大前端' ]
● Limited volume
type color = 'yellow' | 'orange' | 'blue'
function util(c: color) {}
util('yellow')
○ This color is limited to a few values, and color is used to constrain a variable in the future
○ This variable can only accept these values, which is more similar to enum
What type and interface have in common
1. Both object or function types can be constrained
○ interface
interface User { name: string; age: number }
interface Func { (x: number): number }
○ type
type User = { name: string; age: number }
type Func = (x: number) => number
○ We can see that the two definitions are slightly different, but the later usage is basically the same
2. Extension type
The interface uses extends for inheritance
interface Person {
name: string
age: number
}
// 使用 extends 关键字继承自 Person
interface Student extends Person {
classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }
○ type is implemented using crossovers
type Person = {
name: string
age: number
}
// 使用 交叉(&)
type Student = Person & {
classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }
3. Federation type
The interface uses extends to inherit the type
type Person = {
name: string
age: number
}
// 使用 extends 关键字继承自 Person
interface Student extends Person {
classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }
○ type uses cross(&) to extend the interface
interface Person {
name: string
age: number
}
// 使用 交叉(&)
type Student = Person & {
classRoom: number
}
let s: Student = { name: '千锋大前端', age: 10, classRoom: 1 }
The difference between type and interface
1. Interface supports automatic merging of multiple declarations, type does not support
interface User {
name: string
age: number
}
interface User {
classRoom: string
}
/*
真实的 User 接口
{
name: string
age: number
classRoom: string
}
*/
○ type If you declare a duplicate identifier, an error will be reported
2. Default export syntax for ES6 modular syntax
○ Interface supports default export at the same time as declaration
export default interface User {
name: string
age: number
}
○ type must be declared first, in default export
type User = {
name: string
age: number
}
export default User
○ You must declare it first, when the default export is performed, if you directly write the default export, an error will be reported
3. type You can use the typeof keyword to get a certain data type
let box = document.querySelector('.box')
type EleType = typeof box
○ Here defines an EleType identifier that automatically restricts the type of box detected according to the typeof keyword
4. type supports using the in keyword to traverse into mapped types
type names = 'firstName' | 'lastName' | 'AKA'
type nameType = {
[key in names]: string
}
/*
真实的 nameType 类型
{
firstName: string
lastName: string
AKA: string
}
*/