TypeScript:强制将变量识别为一种类型而不进行强制转换

Carter Li

我正在努力进行 TypeScript 的类型检查。例如下面的代码:

export function deepClone<T>(obj: T): T { // make sure that deepClone generates the same type as obj
  if (obj == null || typeof obj !== 'object') {
    return obj;
  }

  switch (Object.prototype.toString.call(obj)) {
    case '[object Array]': {
      const result = new Array(obj.length);
      for (let i=0; i<result.length; ++i) {
        result[i] = deepClone(obj[i]);
      }
      return result as any as T;
    }

    // Object.prototype.toString.call(new XxxError) returns '[object Error]'
    case '[object Error]': {
      const result = new obj.constructor(obj.message);
      result.stack = obj.stack; // hack...
      return result;
    }

    case '[object Date]':
    case '[object RegExp]':
    case '[object Int8Array]':
    case '[object Uint8Array]':
    case '[object Uint8ClampedArray]':
    case '[object Int16Array]':
    case '[object Uint16Array]':
    case '[object Int32Array]':
    case '[object Uint32Array]':
    case '[object Float32Array]':
    case '[object Float64Array]':
    case '[object Map]':
    case '[object Set]':
      return new obj.constructor(obj);

    case '[object Object]': {
      const keys = Object.keys(obj);
      const result: any = {};
      for (let i=0; i<keys.length; ++i) {
        const key = keys[i];
        result[key] = deepClone(obj[key]);
      }
      return result;
    }

    default: {
      throw new Error("Unable to copy obj! Its type isn't supported.");
    }
  }
}

我在const result = new Array(obj.length). 我知道 obj 的类型是,any[]但 ts 编译器无法识别它。我必须编写丑陋的const tmp = obj as any as any[]代码,但它会导致额外无用的代码生成,或者我必须obj as any as whatever在使用的每一行中编写obj

写入function deepClone<T extends any>(obj: T): T有效,但它禁用了大多数类型检查。

另一个案例:

const el = document.getElementById('sth');
switch (el.tagName) {
  case 'INPUT': // Now I know el is a HTMLInputElement element
    el.value = '123'; // Error: HTMLElement doesn't contain property 'value'
    (el as HTMLInputElement).value = '123'; // works
    (el as HTMLInputElement).valueAsNumber = 123; // again
    (el as HTMLInputElement).valueAsDate = xxx; // unacceptable
提香·切尔尼科娃-德拉戈米尔

如果你想更接近无断言的代码,你将需要使用类型保护。有几种可能的类型保护,但打开的结果toString不是其中之一。使用instanceof和自定义类型保护的版本可能是:

export function deepClone<T
    extends
    number | string | boolean |
    Array<any> |
    Error |
    Date | RegExp |
    Int8Array | Uint8Array | Uint8ClampedArray |
    Int16Array | Uint16Array |
    Int32Array | Uint32Array |
    Float32Array | Float64Array | Map<any, any> | Set<any>>(obj: T): T { // make sure that deepClone generates the same type as obj
    if (obj == null || typeof obj !== 'object') {
        return obj;
    }

    if (obj instanceof Array) {
        const result = new Array(obj.length);
        for (let i = 0; i < result.length; ++i) {
            result[i] = deepClone(obj[i]);
        }
        return result as any as T;
    }
    else if (obj instanceof Error) {
        const constructor = obj.constructor as new (p: any) => T & Error;
        const result = new constructor(obj.message);
        result.stack = obj.stack;
        return result;
    }
    else if (obj instanceof Date || obj instanceof RegExp ||
        obj instanceof Int8Array || obj instanceof Uint8Array || obj instanceof Uint8ClampedArray ||
        obj instanceof Int16Array || obj instanceof Uint16Array ||
        obj instanceof Int32Array || obj instanceof Uint32Array ||
        obj instanceof Float32Array || obj instanceof Float64Array || obj instanceof Map || obj instanceof Set) {

        const constructor = obj.constructor as new (p: T) => T;
        return new constructor(obj);
    }
    else if (isObject(obj)) {
        const keys = Object.keys(obj);
        const result: any = {};
        for (let i = 0; i < keys.length; ++i) {
            const key = keys[i];
            result[key] = deepClone(obj[key]);
        }
        return result;
    } else {
        throw new Error("Unable to copy obj! Its type isn't supported.");

    }

    function isObject(obj: object | T): obj is { [k: string]: any } {
        return typeof obj === 'object'
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将列表强制转换为另一种类型,并更改其每个元素的变量

来自分类Dev

C#将对象强制转换为存储在字符串变量中的另一种类型

来自分类Dev

C#将对象强制转换为存储在字符串变量中的另一种类型

来自分类Dev

c:更改变量类型而不进行强制转换

来自分类Dev

将一种类型转换为另一种类型

来自分类Dev

将一种类型的列表转换为另一种类型

来自分类Dev

将一种类型的 Observable 转换为另一种类型

来自分类Dev

如何将一种类型的CompletableFuture转换为另一种类型?

来自分类Dev

如何将嵌套对象从一种类型转换为另一种类型

来自分类Dev

C#-将异步任务从一种类型转换为另一种类型

来自分类Dev

使用已注册的lambda将一种类型转换为另一种类型的类

来自分类Dev

创建将一种类型的函数转换为另一种类型的函数

来自分类Dev

将每月数据从一种类型转换为另一种类型

来自分类Dev

如何将一种类型的对象(接口)转换为另一种类型(接口)?

来自分类Dev

无法将一种类型转换为另一种类型错误

来自分类Dev

如何将一种类型的对象数组转换为另一种类型?

来自分类Dev

将一种类型的数据转换为另一种数据的设计模式

来自分类Dev

将一种类型的列表转换为另一种RXJava?(等效于Javascript映射)

来自分类Dev

为什么在不进行强制转换的情况下将任何内容转换为更具体的类型

来自分类Dev

在捕获错误时将值从一种类型转换为另一种类型的函数

来自分类Dev

是否可以将总位数相同的一种类型的位域转换为另一种类型的位域?

来自分类Dev

为什么我可以将一种类型的数组存储在另一种类型的变量中?

来自分类Dev

将选项中的值转换为另一种类型

来自分类Dev

C#将ObservableCollection转换为另一种类型

来自分类Dev

Form1是一种类型,但用作变量

来自分类Dev

Java继承而不进行强制转换

来自分类Dev

传递对象的实现而不进行强制转换

来自分类Dev

从一种类型转换为另一种类型时的模板类型推导

来自分类Dev

无法将ActionBarActivity解析为一种类型

Related 相关文章

  1. 1

    将列表强制转换为另一种类型,并更改其每个元素的变量

  2. 2

    C#将对象强制转换为存储在字符串变量中的另一种类型

  3. 3

    C#将对象强制转换为存储在字符串变量中的另一种类型

  4. 4

    c:更改变量类型而不进行强制转换

  5. 5

    将一种类型转换为另一种类型

  6. 6

    将一种类型的列表转换为另一种类型

  7. 7

    将一种类型的 Observable 转换为另一种类型

  8. 8

    如何将一种类型的CompletableFuture转换为另一种类型?

  9. 9

    如何将嵌套对象从一种类型转换为另一种类型

  10. 10

    C#-将异步任务从一种类型转换为另一种类型

  11. 11

    使用已注册的lambda将一种类型转换为另一种类型的类

  12. 12

    创建将一种类型的函数转换为另一种类型的函数

  13. 13

    将每月数据从一种类型转换为另一种类型

  14. 14

    如何将一种类型的对象(接口)转换为另一种类型(接口)?

  15. 15

    无法将一种类型转换为另一种类型错误

  16. 16

    如何将一种类型的对象数组转换为另一种类型?

  17. 17

    将一种类型的数据转换为另一种数据的设计模式

  18. 18

    将一种类型的列表转换为另一种RXJava?(等效于Javascript映射)

  19. 19

    为什么在不进行强制转换的情况下将任何内容转换为更具体的类型

  20. 20

    在捕获错误时将值从一种类型转换为另一种类型的函数

  21. 21

    是否可以将总位数相同的一种类型的位域转换为另一种类型的位域?

  22. 22

    为什么我可以将一种类型的数组存储在另一种类型的变量中?

  23. 23

    将选项中的值转换为另一种类型

  24. 24

    C#将ObservableCollection转换为另一种类型

  25. 25

    Form1是一种类型,但用作变量

  26. 26

    Java继承而不进行强制转换

  27. 27

    传递对象的实现而不进行强制转换

  28. 28

    从一种类型转换为另一种类型时的模板类型推导

  29. 29

    无法将ActionBarActivity解析为一种类型

热门标签

归档