一、语言类型概述
我们在类型安全方面分为:强类型和弱类型,在类型检查方面分为:静态类型和动态类型。
- 强类型语言不允许任意的隐式类型转换。
- 弱类型语言则允许任意的数据隐式类型转换。
- 静态类型:一个变量声明它的类型就是明确的,变量类型声明过后不许被修改。
- 动态类型:变量类型声明过后可以被修改。
JavaScript类型系统特征--弱类型&&动态类型
弱类型有一定的安全隐患
强类型优势
- 错误更早暴露
- 代码更智能,编码更准确
- 重构更牢靠
- 减少不必要的类型判断
Flow--js的类型检查器
二、TypeScript--js的超集
优点:TypeScript支持任何一种js运行环境,功能更强大、生态更健全、更完善。目前angular和vue3都是用ts.
缺点:语言本身多了很多概念,项目初期会增加开发成本
ts编译
npm install typescript -g 进行全局安装
新建1.ts文件
tsc 1.ts 会编译生成一个1.js文件
1.原始类型
const c1: string = 'cbc'
const c2: number = 100
const c2_2: number = NaN
const c2_3: number = Infinity//无穷
const c3: undefined = undefined
const c4: null = null
const c5: boolean = true
const c6: void = undefined
const c7:symbol = Symbol()
自己安装ts使用 但是遇es6语法报错
target:转换成的目标语言。就是我们通过ts将代码转为那种语言标准。当前例子中是常用的es5. lib:需要被转义的语言。不写的话默认es5。当前例子增加了es6。解决了Symbol报错。dom是解决console的报错。
2.Object类型
//1
const a: Object = {}
const a1: Object = []
const a2: Object = function () { }
//2
const b: {} = {}
const b1: { foo: number, bar: string } = { foo: 123, bar: 'lcj' }
3.数组类型
//1
const a: Array<number> = [1, 2, 3]
//2
const a2: number[] = [1, 2, 3]
4.元组类型
const tuple: [number, string] = [123, 'lcj']
//1
const age = tuple[0]
const name = tuple[1]
console.log(age, name)//123 "lcj"
//2
const [age,name] = tuple
元组类型例子
5.枚举类型 -- enum
enum status {
a = 0,
b = 1,
c = 2
}
const post = {
name: 'xinxin',
age: status.c
}
console.log(post)//{name: "xinxin", age: 2}
不赋值的话,从0开始自增
enum status {
a,
b,
c
}
const post = {
name: 'xinxin',
age: status.c
}
console.log(post)//{name: "xinxin", age: 2}
第一个赋值,接下来自增
enum status {
a = 8,
b,
c
}
const post = {
name: 'xinxin',
age: status.c
}
console.log(post)//{name: "xinxin", age: 10}
字符串就正常写,无法自增
enum status {
a = 'name',
b = 'age',
c = 'hobby'
}
6.函数类型
function f1(a: number, b: number):string {
return 'abc'
}
f1(100,10)
可选参数 ?
function f1(a: number, b?: number):string {
return 'abc'
}
f1(100)
或者 设置默认值
function f1(a: number, b: number=10):string {
return 'abc'
}
f1(100)
可选参数必须放在参数最后!!!
const f2: (a: number, b: number) => string = function (a: number, b: number): string {
return 'fn2'
}
7.任意类型
//1
function f3(value: any) {
return value
}
f3('string')
f3(100)
f3(true)
//2
let foo: any = 'string'
foo = 100
foo.bar()
不要轻易使用,因为不会进行类型检查。有时需要兼容老代码,所以可能会使用。
8.隐式类型推断
let age = 18
age = 'weee'//error!! let age: number 不能将类型“"weee"”分配给类型“number”
隐式类型推断age是number类型,所以报错。建议为每个变量添加明确类型!
9.类型断言--as
const nums = [110, 120, 124]
const res = nums.find(i => i > 0)
//推荐使用
const num1 = res as number
//不推荐--因为JSX下不能使用
const num2 = <number>res
10.接口
interface Post {
title: string
content:string
}
function printPost(post: Post) {
console.log(post.title)
}
接口可选成员和只读成员
interface Post {
title: string
content: string
subTiltle?: string //可选成员
readonly hobby:string //只读成员
}
function printPost(post: Post) {
console.log(post.title)
}
动态接口
interface Cache {
[prop:string]:string
}
const cache: Cache = {}
cache.foo='val1'
11.类的基本使用
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi(msg: string): void {
console.log(`i am ${this.name},${msg}`)
}
}
12.类的访问修饰符
class Person {
public name: string//默认
private age: number //私有属性
protected gender:boolean //受保护的
constructor(name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi(msg: string): void {
console.log(`i am ${this.name},${msg}`)
}
}
const tom = new Person('tom', 18)
console.log(tom.name)
console.log(tom.age)//error:属性“age”为私有属性,只能在类“Person”中访问。
console.log(tom.gender)//error:属性“gender”受保护,只能在类“Person”及其子类中访问。
class Person {
public name: string//默认
private age: number //私有属性
protected gender:boolean //受保护的
constructor(name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi(msg: string): void {
console.log(`i am ${this.name},${msg}`)
}
}
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)//ok 可以在子类中访问
}
}
构造函数的访问修饰符
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)//ok
}
}
const jack = new Student()//error:类“Student”的构造函数是私有的,仅可在类声明中访问。
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)//ok
}
static create(name: string, age: number) {
return new Student(name, age)
}
}
const jack = Student.create('jack',10)//ok
private私有的不能在外部实例化和继承,内部创建静态方法,在方法内部实例化,因为只允许在内部被访问。
protected 也不能在外部被实例化,但是可以被继承。
13.类的只读属性
class Person {
public name: string//默认
private age: number //私有属性
protected readonly gender:boolean //受保护的
constructor(name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi(msg: string): void {
console.log(`i am ${this.name},${msg}`)
}
}
readonly只读属性,内部外部都不允许被修改!
14.类与接口
interface EatAndRun {
eat(food: string): void
run(distance:number):void
}
class Person implements EatAndRun {
eat(food: string): void {
//...
}
run(distance: number): void {
//...
}
}
一个类型约束一个能力,一个类型同时去实现多个接口
interface Eat {
eat(food: string): void
}
interface Run {
run(distance:number):void
}
class Person implements Eat,Run {
eat(food: string): void {
//...
}
run(distance: number): void {
//...
}
}
15.抽象类
只能被继承不能用new去创建实例对象了,父类中有抽象方法子类必须去实现
abstract class Animal {
eat(food: string): void {
//...
}
abstract run(distance: number): void
}
class Dog extends Animal {
run(distance: number): void {
//...
}
}
const d = new Dog()
d.eat('好东西')
d.run(100)
16.泛型 -- T
在声明函数时先不去定义函数和参数的类型,在调用时在传入确定类型的参数
//只能创建数字类型的
function creatNumArray(lenght: number, value: number): number[] {
const arr = Array<number>(lenght).fill(value)
return arr
}
//泛型 --支持创建任意类型啦
function creatArray<T>(lenght: number, value: T): T[] {
const arr = Array<T>(lenght).fill(value)
return arr
}
const res = creatArray<string>(3,'foo')
17.类型声明
一个成员在被定义是因为某种原因没有明确类型声明,为了考虑兼容一些js模块
import { camelCase } from 'lodash'//error :无法找到模块“lodash”的声明文件
declare function camelCase(input: string): string
const res = camelCase('hello abc')
如果ts中引用第三方模块,如果模块中不包含引用声明文件,可以尝试去安装对应的声明模块,一般是
@types/xxx,如果ts中没有这个模块,那么使用declare去声明所对应的类型!