invalid_null_aware_operator 진단: null이 될 수 없는 수신자에 null-aware 연산자를 쓸 필요가 없어요

invalid_null_aware_operator 진단: null이 될 수 없는 수신자에 null-aware 연산자를 쓸 필요가 없어요

Dart 분석기가 내보내는 진단에는 이름이 있어요. invalid_null_aware_operatornull이 될 수 없음(non-nullable)이 분명한 수신자(receiver)에 null-aware 연산자(?., ?.., ?[, ?..[, ...?)를 사용했을 때 분석기가 알려주는 컴파일 타임 진단이에요. null 체크가 사실상 의미 없으니 연산자를 제거하는 게 좋아요.

출처: invalid_null_aware_operator

본문

설명

분석기는 null-aware 연산자(?., ?.., ?[, ?..[, 또는 ...?)가 null이 될 수 없다고 알려진 수신자에 사용될 때 이 진단을 만들어요.

예시

다음 코드는 s가 null이 될 수 없기 때문에 이 진단을 만들어요.

int? getLength(String s) {
  return s?.length;
}

다음 코드는 a가 null이 될 수 없기 때문에 이 진단을 만들어요.

var a = [];
var b = [...?a];

다음 코드는 s?.length가 null을 반환할 수 없기 때문에 이 진단을 만들어요.

void f(String? s) {
  s?.length?.isEven;
}

s?.length가 null을 반환할 수 없는 이유는, s 다음의 null-aware 연산자가 s가 null이면 lengthisEven의 평가를 모두 단락(short-circuit)시키기 때문이에요. 다시 말해, s가 null이면 lengthisEven도 호출되지 않고, s가 null이 아니면 length는 null 값을 반환할 수 없어요. 어느 쪽이든 isEven은 null 값에 대해 호출될 수 없으므로 null-aware 연산자가 필요 없어요. 자세한 내용은 Understanding null safety를 참고하세요.

다음 코드는 s가 null이 될 수 없기 때문에 이 진단을 만들어요.

void f(Object? o) {
  var s = o as String;
  s?.length;
}

o는 null일 수 있음에도 s가 null이 될 수 없는 이유는, null이 아닌 타입인 String으로의 캐스트 때문이에요. o가 값이 null이면 캐스트가 실패하고 length의 호출은 일어나지 않아요.

다음 코드는 s가 null이 될 수 없기 때문에 이 진단을 만들어요.

List<String> makeSingletonList(String s) {
  return <String>[?s];
}

흔한 해결 방법

null-aware 연산자를 null-aware가 아닌 동등한 연산자로 바꿔주세요. 예를 들어 ?..으로 바꿔요.

int getLength(String s) {
  return s.length;
}

(참고로 반환 타입도 null이 될 수 없는 타입으로 바뀌었는데, 어떤 경우에는 이것이 적절하지 않을 수도 있어요.)

더 알아보기