如何在打字稿中键入非空数组?

时间:2021-04-13 11:35:04

标签: javascript typescript types casting type-conversion

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

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

我需要这个是为了确保数组不是空的,所以如果它是空的,那么访问它的任何元素将立即返回 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

2 个答案:

答案 0 :(得分:1)

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

Playground(链接开启了 # Add two numbers layout code BoxLayout: spacing: 1 orientation:'vertical' pos_hint: {'x': 0, 'y': 0} background_color: .7,.7,.7,1 canvas.before: Color: rgba: .7, .7, .7, 1 Rectangle: size: self.size pos: self.pos ColorLabel: text: "Enter two numbers to add" TextInput: id: frnum size_hint: (None, .8) width: 150 anchor_x: 'center' TextInput: id: secnum size_hint: (None, .8) width: 150 anchor_x: 'center' # horizontal box contains two buttons BoxLayout: spacing: 10 orientation:'horizontal' canvas.before: Color: rgba: .7, .7, .7, 1 GrayButton: text: 'Add' color: 0,0,0,1 on_release: app.bclick() GrayButton: text: 'Clear' on_release: app.cclick() ColorLabel: text: "Sum appears here" id: sumlabel <ColorLabel@Label>: color: 0,0,1,1 size: self.texture_size canvas.before: Color: rgba: .9, .9, .9, 1 Rectangle: pos: self.pos size: self.size padding_x: 20 background_color: .7,.7,.7,1 <GrayButton@Button>: color: 0,0,0,1 background_normal: '' background_color: .8,.8,.8,1 padding_horizontal: 20 size_hint: (0.5,0.7) pos_hint: {'x':.2, 'y':.2, 'center_x':.5} from kivy.app import App from kivy.core.window import Window from kivy.config import Config class MainApp(App): def build(self): #self.title = "Add two numbers" Window.size = (300, 200) self.load_kv('Bldtest1.kv') # Add click event def bclick(self): textinput = self.root.ids.frnum val1= int(textinput.text) tinput = self.root.ids.secnum val2 = int(tinput.text) sum_label = self.root.ids.sumlabel sum_label.text = "Sum is: "+ str(val1+val2) # Clear button click event def cclick(self): textinput = self.root.ids.frnum textinput.text = '' tinput = self.root.ids.secnum tinput.text = "" sum_label = self.root.ids.sumlabel sum_label.text ='' MainApp().run() 标志)。

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

答案 1 :(得分:0)

我设法让 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 元素

相关问题