【问题标题】:How to type a non-empty array in typescript?如何在打字稿中键入非空数组?
【发布时间】:2023-04-02 21:38:02
【问题描述】:

如果未预先检查数组是否为空,我希望打字稿编译器在尝试直接访问数组的任何元素时抛出“对象可能是“未定义”错误,因此您始终必须检查该元素对于未定义,例如,使用可选链接

如果预先检查了数组不为空,那么你需要能够像往常一样访问它的元素,而不需要检查它的元素是否未定义

我需要这个以确保数组不为空,因此如果它为空,则对其任何元素的访问将立即返回 undefined 然后链接将不会继续,并且不会出现无法读取等可能的错误未定义的属性

我该怎么做?

代码示例,也许它会让我的问题更清楚

interface Element {
  a: {
    aa: string;
    bb: string;
  };
  b: {
    aa: string;
    bb: string;
  };
}

const element: Element = {
  a: { aa: "aa", bb: "bb" },
  b: { aa: "aa", bb: "bb" },
};

type ElementArray = Element[];

const array: ElementArray = [element, element];
const emptyArray: ElementArray = [];

const getFirstAWithoutLengthCheck = (array: ElementArray) => {
  return array[0].a; // i want the typescript compiler to throw an 'Object is possibly 'undefined'' error here
};

const getFirstAWithLengthCheck = (array: ElementArray) => {
  if (array.length) {
    return array[0].a; // shouldn't be any errors
  }
  return null;
};

const getFirstAOptChaining = (array: ElementArray) => {
  return array[0]?.a; // shouldn't be any errors
};

// will throw error cannot read property a of undefined, so we need to use
// optional chaining or length check in this function, but typesript is not requiring it
console.log(getFirstAWithoutLengthCheck(array)); // aa
console.log(getFirstAWithoutLengthCheck(emptyArray)); // crash!

// checking array length, access to first element should work as usual, no errors
console.log(getFirstAWithLengthCheck(array)); // aa
console.log(getFirstAWithLengthCheck(emptyArray)); // null

// optional chaining, no errors
console.log(getFirstAOptChaining(array)); // aa
console.log(getFirstAOptChaining(emptyArray)); // undefined

【问题讨论】:

标签: javascript typescript types casting type-conversion


【解决方案1】:

正如@Roberto Zvjerković 所说,您需要使用noUncheckedIndexedAccess 编译器标志。

Playground(链接已打开noUncheckedIndexedAccess 标志)。

但是,你需要使用if (array.length),而不是if (array[0])。这是因为,即使长度不为零,也不能确保元素是“未定义的”。如果数组是array = [undefined],它应该给出运行时错误。它与数组的类型无关,它是否可以包含undefined

【讨论】:

    【解决方案2】:

    我设法让 TypeScript 在第一个示例中抛出一个错误,而不是在第三个示例中抛出一个错误,但遗憾的是它在第二个示例中给出了未定义的错误。希望这对您有所帮助:

    interface Element {
      a: {
        aa: string;
        bb: string;
      };
      b: {
        aa: string;
        bb: string;
      };
    }
    
    const element: Element = {
      a: { aa: "aa", bb: "bb" },
      b: { aa: "aa", bb: "bb" },
    };
    
    type ElementArray = [] | [Element] | [Element, ...Element[]];
    
    const array: ElementArray = [element, element];
    const emptyArray: ElementArray = [];
    
    const getFirstAWithoutLengthCheck = (array: ElementArray) => {
      return array[0].a; // i want the typescript compiler to throw an 'Object is possibly 'undefined'' error here
    };
    
    const getFirstAWithLengthCheck = (array: ElementArray) => {
      if (array.length) {
        return array[0].a; // shouldn't be any errors
      }
      return null;
    };
    
    const getFirstAOptChaining = (array: ElementArray) => {
      return array[0]?.a; // shouldn't be any errors
    };
    
    // will throw error cannot read property a of undefined, so we need to use
    // optional chaining or length check in this function, but typesript is not requiring it
    console.log(getFirstAWithoutLengthCheck(array)); // aa
    console.log(getFirstAWithoutLengthCheck(emptyArray)); // crash!
    
    // checking array length, access to first element should work as usual, no errors
    console.log(getFirstAWithLengthCheck(array)); // aa
    console.log(getFirstAWithLengthCheck(emptyArray)); // null
    
    // optional chaining, no errors
    console.log(getFirstAOptChaining(array)); // aa
    console.log(getFirstAOptChaining(emptyArray)); // undefined
    

    TypeScript playground 忽略元素上的错误,TypeScript playground 认为元素是 DOM 元素

    【讨论】:

      猜你喜欢
      • 2020-12-04
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 2020-09-24
      • 1970-01-01
      • 2023-03-29
      • 2021-03-09
      相关资源
      最近更新 更多