--strictPropertyInitialization
参数开启时,calss 的属性必须在构造函数中定义初始值。可以在属性后面添加 ! 来关闭提示。
class BadGreeter{
// Property 'name' has no initializer and is not definitely assigned in the constructor.
name: string
}
构造函数
重载
class Point {
constructor(x:number, y:number);
constructor(s:string)
}
注意:构造函数不能有类型参数;构造函数不能返回类型。
get/set
1. 只有get,没有set ----> readonly
2. set 参数没有类型,会自动从 get 的返回值推导类型
3. get/set 必须有相同的 Member Visibility,即 private、public、protected
注意:TS 4.3 中 set/get 可以有不同的类型的 value。
implement
类必须满足一个特定的 interface,可以实现多个 interface。
class C implements A, B{
//
}
注意
1. implement 只检查类是不是可以被作为一个 interface。Mehtod 的类型是不会被 implement 改变的。
下方会报错。直觉上会认为 check 方法的参数 s 必然是一个 string。但实际上 implement 后并不会改变 class 内 mtehod 的类型。s 会被稳定为 any。
interface Checkable{
check(name: string): boolean;
}
class NameChecker implements Checkable{
check(s){
returnt s.toLowercse() === 'ok'
}
}
2. 可选属性
interface A{
x: number;
y?: number;
}
class C implement A{
x = 0
}
cosnt c = new C()
// 报错
c.y = 10
extends
衍生类继承基类的所有属性和方法,并且可以扩展。
方法重写 Overriding Methods
衍生类可以重写基类的方法,但是方法必须有相同接口。下方报错。
class Base{
greet(){
console.log("Hello, World!")
}
}
class Drived extends Base{
// 接口不一致 报错
greet(name: string){
console.log(name)
}
}
类的初始化顺序
1. 基类字段初始化
2. 基类构造函数初始化
3. 衍生类字段初始化
4. 衍生类构造函数初始化
内建类型的继承 ---> 适用于ES5
ES5 中派生类的 this 是由派生类创建,再由基类改造;ES6及以后,派生类的 this 是由基类创建,再由派生类改造。
因此:
1. ES5 中,派生类的某些方法可能不存在
2. instanceof 操作符应用在派生类及其实例的时候会失效;( new MsgError() ) instanceof MsgError ---> false
class MsgError extends Error{
constructor(m:string){
super(m);
}
sayHello(){
return this.message
}
}
挽救方法 ( IE10 及其之前都无效 )
手动调整原型链
class MsgError extends Error{
constructor(m:string){
super(m)
// 调整一下原型链
Object.setPrototyeOf(this, MsgError.prorotype)
}
}
注意:MsgError 的子类也要手动设置原型链
**个人理解:**ES6 中衍生类修饰 基类创建的 this,然后衍生类构造函数返回修饰后的 this 。TS 中的表现与 ES6 一样,但是 TS ---> ES5 及以下的时候,旧语法不支持此特性,因此要手动调整原型链。
类成员可见度 Member Visiblity
public:在 类 的外部任何地方都可以访问类的属性、方法
protected:只能在 子类 中访问基类的方法、属性,不能在 基类 外部访问
下述情况再不同的 OOP 语言中行为不同。在TS/C#/C++中,下述 Derived2 类的 f2 方法是不合法的。因为直接访问的是 基类的 protected 属性。
class Base {
protected x: number = 1
}
class Derived1 extends Base{
protected x: number = 5
}
class Derived2 extends Base{
f1(other: Derived2){
other.x = 10
}
// Property 'x' is protected and only accessible through an instance of class 'Derived2'.
// This is an instance of class 'Base'.
f2(other: Base){
other.x = 10
}
}
private:只能在类内部访问属性、方法
在 TS 中,在某一类的一众实例中,其中一个实例的方法可以访问其余实例的私有成员。貌似和private行为相反?
而 Java,C# 之类的语言并不能。
class A{
private x = 10
public sameAs(other: A){
// work
return other.x === this.x
}
}
JavaScript的私有属性:developer.mozilla.org/en-US/docs/…
静态成员
只能被类的构造函数调用,其实就是构造函数上添加了一众属性、方法。
静态成员也可以使用 plublic,protected,private修饰。
保留字:name、length、call 等 Function 的属性是不能被定义成静态成员的。
静态类
TS 中不存在静态类
JAVA,C# 等语言中,并不允许方法、属性脱离 class 单独存在,因此只能通过 静态类的方法实现 TS/JS 中的功能。
// 其他语言的写法
class MyStaticClass{
static doSomething() {}
}
// TS/JS 的写法一
function doSomething() {}
// TS/JS 的方法二
const MyHelperObject = {
dosomething() {}
}
泛型类
静态方法的类型:TS 中静态成员是不可以设置泛型的。反向思考一下,如果下方Box 一个实例的 Box.defaultValue 的值被的设为一个 string 类型的。那么另一个实例 Box.defaultValue 的值就成了 string,而不是 number。
class Box<T>{
// Static members cannot reference class type parameters.
static defaultValue:T
}
运行时 runtime
TS 并不改变 JS 的运行时逻辑,因此,与 JS 一样会有诡异的行为。
what‘s this in JS?
箭头函数
箭头函数的 this 是词法作用域。
1. 可以保证 this 的值永远正确,避免一些诡异行为
2. 占用内存更多,每个使用箭头函数写法的类实例,都会保存一遍 this 的值
3. 在派生类中并不能使用 super.getName。因此箭头函数的写法并不会保存在原型链上
class MyClass{
name = "MyClass"
getName = () =>{
return this.name
}
}
const c = new MyClass()
const g = c.getName
// Prints "MyClass" instead of crashing
console.log(g())
this parameters
this 作为函数的参数时,TS 会抹去 this。
// TS 中的写法
function fn(this: SomeType, x:number){}
// 转化为 JS 后,等价于下方
function fn(x) {}
在method 中,通过传入 MyClass 类型的 this 参数以保证 方法的 上下文是正确的。同样地,在运行时中,this 参数会被抹去。同样地,在global context 执行 getName 会报错。
class MyClass{
name = "MyClass"
getName(this: MyClass){
return this.name
}
}
const c = new MyClass()
c.getName()
// crash
const g = c.getName
g()
this 类型 ---> this Types
TS 中, class 可以使用 this 类型。
class Box{
content = string = ""
sameAs(other:this){
return other.content === this.content
}
}
class DerivedBox extends Box {
otherContent: string = "?"
}
const base = new Box
const derived = nwe DerivedBox
derived.sameAs(base)
this 作为类型守卫
使用 this 结合 其他类型守卫 手段可以将目标对象收缩到特定的 类型。
下方案例中 this is Networked & this 理解是 this is (Networked & this)。isNetwork() 函数执行后,更改了 this 的类型,因此 FileRep 类有了 Networked 的类型,即,将对象收缩到特定类型。
class FileSystemObejct{
isFile(): this is FileRep{
return this instanceof FileRep
}
isDirectory():this is Directory {
reutn this instanceof Directory
}
isNetworked(): this is Networked & this{
return this.networked
}
constructor(public path: string, private networked: bolean){}
}
class FileRep extends FileSystemObject{
constructor(path:string, public content:string){
super(path, false)
}
}
class Directory extends FileSystemObject{
children: FileSystemObejct[]
}
interface Networked{
host: string
}
const fso: FileSystemObject = new FileRep("foo/bar.text", "foo")
if(fso.isFile()){
// FileRep
fso.content;
}else if(fso.isDirectory()){
// Directory
fso.children
}else if (fso.isNetworked()){
// Networked & FileSystemObject
fso.host
}
普遍用法
这个案例中,利用 this is 去移除 value 的 undefined 类型。
class Box<T>{
value?: T
hasValue(): this is {value: T}{
return this.value !== undefined
}
}
const box = new Box()
// (property) Box<unknow>.value?: unknown
box.value = "Gameboy"
if(box.hasValue()){
// value: unknown
box.value
}
Parameter Properties
TS 中类的构造函数可以不用给构造函数的变量赋值,TS 会创建与参数类型相同的 类属性,并且在构造函数执行的时候 赋值。
class Params{
cosntructor(
public readonly x: number,
protected y: number,
private z: number
){
// no body necessary
}
}
const a = new Params(1, 2, 3)
// work
console.log(a.x)
// crash
console.log(a.z)
类表达式 Class Expressions
下方的类表达式写法与直接声明一个类的效果相同,但是不同的是在表达式中可以省略类的名称。
const someClass = class<T> {
content:T;
constructor(value:T){
this.content = value;
}
}
抽象类与类成员 abstract Classes and Members
抽象方法或属性并不需要提供其实现,且只能存在抽象类中。抽象类并不能直接被实例化,通常用作基类。其派生类必须实现其类的抽象方法,否则会报错。
abstract class Base{
abstract getName():String;
printName(){
console.log(`hello, ${this.getName()}`)
}
}
// crash
const b = new Base()
class Derived extends Base{
getName(){
return "world";
}
}
const d = new Derived();
// work
d.printName()
在某些情况下,可能想接收类的构造函数,并且创建类的实例,但是碰到抽象类会报错。
下方,街上上述抽象类 Base
function greet(ctor: typeof Base){
// crash
const instance = new ctor()
instance.printName()
}
function greet1(ctor: new () => Base){
const instance = new Ctor()
instance.printName()
}
// work
greet(Derived)
// crash
// Cannot assign an abstract constructor type to a non-abstract constructor type.
greet(Base)
类之间的关系
大多数情况下,TS 只会比较类的结构。
class Point1{
x = 0;
y = 0;
}
class Point2{
x = 0;
y = 0;
}
// work
const p: Point1 = new Point2()
class Person{
name: string;
age: number;
}
class Employee{
name: string;
age: number;
salary: number;
}
// work
const p1: Person = new Employee()
// crash
const p2: Employee = new Person()
Empty Class:空类没有任何成员,在结构化的类型系统中,空类是任何对象的超类。
class Empty{}
function fn(x: Empty){
// ...
}
// All OK!
fn(window)
fun({})
fn(fn)
参考
www.typescriptlang.org/docs/handbo…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!