函数公式究竟是不是双重协变的?

lxf2023-05-23 00:57:31

填上一篇文章所提到的函数公式双重协变坑

函数公式究竟是不是双重协变的?

假如你回答道打开 strictFunctionTypes 并不是,不打开便是。可以看下题

// 假定打开了 strictFunctionTypes
interface Person {
  name: string;
  age: number;
}


// Student 是 Person 的子类型
interface Student extends Person {
  getStatus(): string;
}

interface Worker extends Person {
  coding: boolean;
}

// 留意 method 用这种方法的概念方法
interface Test<T> {
  method(a: T): number;
}

declare let studentTest: Test<Student>;
declare let personTest: Test<Person>;

// 不容易出错,strictFunctionTypes 并没有起效
personTest = studentTest; // Ok 
studentTest = personTest; // Ok

// ⚠️ 假如我们改下 Test 中 method 的概念方法

// 留意 method 用这种方法的概念方法
interface Test<T> {
  method: (a: T) => number;
}

// 此次达到预期的效果
personTest = studentTest; // error
studentTest = personTest; // ok

注重总结一下:函数公式做为目标里的属性情况下,他界定不同。实际效果完全不一样

函数公式方式

不会受到 strictFunctionTypes 设定的危害,持续保持双重协变。

interface Test<T> {
  // 这类叫函数公式方式
  method(a: T): number;
}

函数公式特性

interface Test<T> {
  // 这类叫函数公式方式
  method(a: T): number;
}

受 strictFunctionTypes 设定的危害,为true乃是逆变电源,不然双重协变。

为何

只要我们把ts编译成js,大家就懂了。

class Test {
  method() {
    // 这也是函数公式方式
  }
  property = () => {
    // 这也是函数公式特性
  }
}

// 编译程序后
var Test = /** @class */ (function () {
    function Test() {
        var _this = this;
        this.property = function () {
            // 这也是函数公式特性
        };
    }

    Test.prototype.method = function () {
        // 这也是函数公式方式
    };

    return Test;
}());

method 被写进了原型对象上,对象的常用办法也写在了原形里的。

记得以前文中,大家提及为了兼容 Array 这样的数据构造,才会导致函数公式最初被设计为双重协变吗?

这也是为什么函数公式方式也只能是 双重协变。因此极力推荐应用 函数公式特性

双重协变难以保证类型安全,因此使用 双重协变 的算法设计一定要小心!

官方说法

// 危险的实例
const students: Student[] = [];

const arr: Person[] = students;

arr1.push({} as Worker);

// 欢迎来到赋值 students 自变量,别看错
// 是因为 students 取值给 arr, 而 arr 调用的 students 里的push 所导致的危险行为
students.forEach((item) => item.getStatus);

class (类)的种类该如何表明?

在ts中,class是为数不多的好多个既能当值应用,又能够当做种类所使用的算法设计。

const ImNull: null = null
const ImUndefined: undefined = undefined

class Test {
    show(){}
}
// ???
const test: Test = new Test()

细心地好朋友看到了,Test 做为类名, 做为种类来使用时,表示是该类的实例。而非类自身

意思是说 const test: Test = Test 这类书写是不正确的。

正确书写是 const test: typeof Test = Test

假如我略微改一下 Test 的概念呢?

class Test {}

// 请问一下下边会不会出错
const test: Test = Test
// 回答在下文

对象

以下这些写法的意义你能够准确了解吗?

declare let fn: Function
declare let str: String
declare let obj: Object

或是下边创立吗?

fn = () => {}
fn = (...args: string[]) => {}
fn = false
fn = Boolean
fn = alert
查看答案 ✅ ✅ ❌ ✅ ✅
str = 'i am string'
str = String
str = Function
str = alert
查看答案 ✅ ❌ ❌ ❌
obj = 'i am string'
obj = Object
obj = function() {}
obj = alert
obj = false
obj = null
查看答案 ✅ ✅ ✅ ✅ ✅ ❌

如果你可以对了上边的所有难题,相信自己的js基本一定非常好!

最先,对象和类的概念要弄明白。实际上上面已经剧通过了,类只是一个对象的一个语法糖。所以大家可以把对象当作类来处理

那样,declare let fn: Function 的内涵便是 fn 的形式是 Function 的案例. 假如你了解 js 的原型链,上边的问题也很简单

fn = () => {} // 这也是箭头函数,因此 ok
fn = (...args: string[]) => {}  // 这是也是箭头函数,因此 ok
fn = false // 
fn = Boolean // Boolean 做为对象,他还是 Function 的案例。我们通过 isntanceOf 来判定
fn = alert // 内置函数,ok

如果对于原型链不太熟或是忘记了,可以参考一下之前的 文章内容

String 非常简单,也不阐述了。下边看看Object

obj = 'i am string' // 这正确,由于 String 传承 自 Object。 'i am string' 是 String 的案例
obj = Object // Object 本身就是函数公式,每一个函数公式全是 Function 的案例。 Function 又传承 Object。 因为这正确
obj = function() {} // 跟上面一样
obj = alert // 跟上面一样
obj = false // false 是 Boolean 的案例, Boolean 传承 Object。 因此恰当
obj = null // 非常明显不正确

JS圈子果真太复杂了,Function 和 Object 的私人生活太乱了

温馨提示,对象便是函数公式,基本上没有区别(除开箭头函数)。能够被 new 关键字调用的函数公式就叫做对象。

Object、object、{} 和 Record 的恩仇纠缠不清

坦白说,最初我写TS时,也总是觉得困惑。就想定一个对象,如何还有那么多的形式。但是现在基本上都是用 Record

Object 上面已经说过,就不多说了

object 比较特殊,他指出非原始类型。即除了 boolean、string、number、null、undefined、symbol 这种原始类型。记得 WeakMap 这一算法设计吗?

// 它键就需要:非原始类型
interface WeakMap<K extends object, V> { }

{} 这一也表示一个空对象。 相近 const obj = new Object() 这个词语。他本身没有特性,但是能够浏览 Object 里的默认方法和特性

但是自从有了 Record 之后,上边都是能够平价替代的。

object 能够写出 Record<string, unknown>

{} 能够写出 Record<string, never>

接着再提一下另一个很不好的写法,一旦发现你朋友这么写,就赶快@他来,看着我锤死他 :)

interface InputProps {
    name: string
    value?: string
    // 这一书写是相当不太好的,就会比 any 强一点
    [x: string]: any
}

完结撒花~

本站是一个以CSS、JavaScript、Vue、HTML为中心的前端开发技术网址。我们的使命是为众多前端工程师者提供全方位、全方位、好用的前端工程师专业知识和技术服务。 在网站上,大家可以学到最新前端开发技术,掌握前端工程师最新发布的趋势和良好实践。大家提供大量实例教程和实例,让大家可以快速上手前端工程师的关键技术和程序。 本站还提供了一系列好用的工具软件,帮助你更高效地开展前端工程师工作中。公司提供的一种手段和软件都要经过精心策划和改进,能够帮助你节约时间精力,提高研发效率。 此外,本站还拥有一个有活力的小区,你可以在社区里与其它前端工程师者沟通交流技术性、交流经验、处理问题。我们坚信,街道的能量能够帮助你能够更好地进步与成长。 在网站上,大家可以寻找你需要的一切前端工程师网络资源,使您成为一名更加出色的网页开发者。欢迎你添加我们的大家庭,一起探索前端工程师的无限潜能!