TypeScript类型级别和值级别如何区分

其他教程   发布日期:2023年07月15日   浏览次数:415

这篇文章主要介绍“TypeScript类型级别和值级别如何区分”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“TypeScript类型级别和值级别如何区分”文章能帮助大家解决问题。

对值级别编程类型级别编程区分

首先,让我们对值级别编程和类型级别编程进行重要区分。

  • 值级别编程让我们编写将在生产中运行的代码即运行期,并为我们的用户提供有用的东西。

  • 类型级别编程帮助我们确保代码在发布之前即编译期不包含错误,在运行期会被完全删除

JavaScript没有类型,所以所有JavaScript都是值级别的代码:

  1. // A simple Javascript function:
  2. function sum(a, b) {
  3. return a + b;
  4. }

TypeScript允许我们将类型注释添加到JavaScript中,并确保我们编写的sum函数永远不会用数字以外的任何东西调用:

  1. // Using type annotations:
  2. function sum(a: number, b: number): number {
  3. return a + b;
  4. }

但TypeScript的类型系统远比这强大得多。我们编写的真实代码有时需要是通用的,并接受我们事先不知道的类型。

在这种情况下,我们可以在尖括号<A,B,&hellip;>中定义类型参数然后,我们可以将类型参数传递给一个类型级函数,该函数根据输入类型计算输出类型:

  1. // Using type level programming:
  2. function genericFunction<A, B>(a: A, b: B): DoSomething<A, B> {
  3. return doSomething(a, b);
  4. }

这就是类型级编程!

  1. DoSomethingAB>
是一种用特殊编程语言编写的类型级函数,它与我们用于值的语言不同,但同样强大。让我们将这种语言称为类型级TypeScript。
  1. // This is a type-level function:
  2. type DoSomething<A, B> = ...
  3. // This is a value-level function:
  4. const doSomething = (a, b) => ...

类型级编程

类型级TypeScript是一种最小的纯函数语言。

在类型级别,函数被称为泛型类型:它们接受一个或多个类型参数并返回单个输出类型。下面是一个函数的简单示例,该函数使用两个类型参数并将它们包装在元组中:

  1. type SomeFunction<A, B> = [A, B];
  2. /* ---- ------
  3. ^
  4. type return type
  5. parameters
  6. -------------------------/
  7. ^
  8. Generic
  9. */

类型级别的TypeScript没有很多功能。毕竟,它是专门为你的代码做类型约束的!也就是说,它确实有足够的特性(几乎)图灵完备,这意味着你可以用它解决任意复杂的问题。

  • 代码分支:根据条件执行不同的代码路径(相当于值级别if/else关键字)。

  • 变量赋值:声明一个变量并在表达式中使用它(相当于值级别var/let关键字)。

  • 函数:可重复使用的逻辑单位,如我们在前面的示例中看到的。

  • 循环:通常通过递归。

  • 相等检查:==但适用于类型!

  • 还有更多!

这是我们将在接下来的章节中学习的语言类型的简要概述。现在,让我们开始第一次挑战吧!

挑战是如何工作的

在每一章结束时,你将有一些挑战需要解决,以将你的新技能付诸实践。它们看起来像这样:

  1. namespace challenge {
  2. // 1. implement a generic to get the union
  3. // of all keys in an object type.
  4. type GetAllKeys<Obj> = TODO;
  5. type res1 = GetAllKeys<{ a: number }>;
  6. type test1 = Expect<Equal<res1, "a">>;
  7. }
    1. namespace
    是一个鲜为人知的TypeScript功能,它可以让我们在专用范围内隔离每个挑战。
    1. TODO
    是占位符。这是您需要更换的!
    1. res1=。。。
    是泛型为某些输入类型返回的类型。您可以用鼠标将其悬停以检查其当前
    1. type test1=Expect<Equal<res1,&hellip;>>
    是类型级单元测试。用于判断
    1. TODO
    部分的代码是否正确

在此之前你要先定义好Expect和Equal

  1. type Expect<T extends true> = T;
  2. type Equal<X, Y> = (<T>() => T extends { [k in keyof X]: X[k]; } ? 1 : 2) extends <T>() => T extends { [k in keyof Y]: Y[k]; } ? 1 : 2 ? true : false;

挑战

准备好迎接你的第一个挑战了吗?出发:

  1. /**
  2. * 1. The `identity` function takes a value of any type
  3. * and returns it. Make it generic!
  4. */
  5. namespace genericFunction {
  6. function identity(a: TODO): TODO {
  7. return a;
  8. }
  9. let input1 = 10;
  10. let res1 = identity(input1);
  11. type test1 = Expect<Equal<typeof res1, number>>;
  12. let input2 = "Hello";
  13. let res2 = identity(input2);
  14. type test2 = Expect<Equal<typeof res2, string>>;
  15. }
  1. /**
  2. * 2. `safeHead` takes an array, a default value
  3. and returns the first element of the array
  4. if it isn't empty. Make it generic!
  5. */
  6. namespace safeHead {
  7. function safeHead(array: TODO[], defaultValue: TODO): TODO {
  8. return array[0] ?? defaultValue;
  9. }
  10. let input1 = [1, 2, 3];
  11. let res1 = safeHead(input1, 0);
  12. type test1 = Expect<Equal<typeof res1, number>>;
  13. let input2 = ["Hello", "Hola", "Bonjour"];
  14. let res2 = safeHead(input2, "Hi");
  15. type test2 = Expect<Equal<typeof res2, string>>;
  16. }
  1. /**
  2. * 3. `map` transforms all values in an array to a value of
  3. * different type. Make it generic!
  4. */
  5. namespace map {
  6. function map(array: TODO[], fn: (value: TODO) => TODO): TODO[] {
  7. return array.map(fn);
  8. }
  9. let input1 = [1, 2, 3];
  10. let res1 = map(input1, value => value.toString());
  11. type test1 = Expect<Equal<typeof res1, string[]>>;
  12. let input2 = ["Hello", "Hola", "Bonjour"];
  13. let res2 = map(input2, str => str.length);
  14. type test2 = Expect<Equal<typeof res2, number[]>>;
  15. }
  1. /**
  2. * 4. `pipe2` takes a value and pipes it into 2 functions
  3. * sequentially. For example, `pipe2(x, f1, f2)` will
  4. * result in `f2(f1(x))`. Make it generic!
  5. *
  6. */
  7. namespace pipe2 {
  8. function pipe2(
  9. x: TODO,
  10. f1: (value: TODO) => TODO,
  11. f2: (value: TODO) => TODO
  12. ): TODO {
  13. return f2(f1(x));
  14. }
  15. let res1 = pipe2(
  16. [1, 2, 3],
  17. arr => arr.length,
  18. length => `length: ${length}`
  19. );
  20. type test1 = Expect<Equal<typeof res1, string>>;
  21. let res2 = pipe2(
  22. { name: 'Alice' },
  23. user => user.name,
  24. name => name.length > 5
  25. );
  26. type test2 = Expect<Equal<typeof res2, boolean>>;
  27. }

以上就是TypeScript类型级别和值级别如何区分的详细内容,更多关于TypeScript类型级别和值级别如何区分的资料请关注九品源码其它相关文章!