avoid_futureor_void 진단: FutureOr 타입을 쓰지 말아야 할 때

avoid_futureor_void 진단: FutureOr 타입을 쓰지 말아야 할 때

Dart 분석기가 내보내는 진단에는 이름이 있어요. avoid_futureor_voidFutureOr<void> 타입을 결과 타입으로 사용했을 때 Dart 분석기가 알려주는 린트(lint) 진단이에요. 이 타입은 결과를 표현할 때 모호함과 개념적인 문제를 일으킬 수 있어요.

출처: avoid_futureor_void

본문

설명

분석기는 FutureOr<void> 타입을 결과(result)의 타입으로 사용했을 때(정확히 말하면 반변(contravariant) 위치가 아닌 곳에 사용했을 때) 이 진단을 만들어요. FutureOr<void> 타입은 결과가 Future<void>이거나 결과를 버려야 한다는 뜻(즉 void)인 것처럼 보이게 만들 수 있어서 문제가 돼요. 하지만 실제로 어느 쪽인지 안전하게 구분할 방법이 없어요. void 타입의 식(expression)은 어떤 객체든 평가될 수 있고, 어떤 타입의 future도 될 수 있기 때문이에요.

또한 "이 객체는 무시하되, 어쩌면 future일 수도 있으니 한번 살펴봐라" 같은 의미를 가진 타입은 개념적으로도 타당하지 않아요.

다만 FutureOr<void> 타입의 반변적(contravariant) 사용(예를 들어 형식 매개변수(formal parameter)의 타입)에는 예외가 적용되고, 이런 사용에는 경고를 내보내지 않아요. 예외를 두는 이유는 이 타입이 결과를 표현하는 게 아니라 다른 쪽에서 제공하는 값에 대한 제약을 표현하기 때문이에요. 마찬가지로 타입 별칭(type alias) 선언에도 예외가 적용돼요. 타입 별칭은 반변적 위치(예를 들어 형식 매개변수의 타입)에서 사용될 수 있기 때문이에요. 그래서 타입 별칭 선언에서는 타입 매개변수의 경계(bound)만 검사해요.

예시

다음 코드는 FutureOr<void>를 결과 타입으로 사용했기 때문에 이 진단을 만들어요.

import 'dart:async';

FutureOr<void> m() => null;

흔한 해결 방법

FutureOr<void> 타입을 대체할 때 자주 유용한 것은 Future<void>?예요. 이 타입은 결과가 Future<void>이거나 null임을 표현하고, 어떤 객체도 두 타입을 동시에 가질 수 없으므로 런타임에서 모호함이 없어요.

하지만 FutureOr<void>Future<void>?로 항상 대체할 수 있는 건 아니에요. 전자는 모든 타입의 상위 타입(supertype)이지만 후자는 그렇지 않기 때문이에요. 이런 경우에는 FutureOr<void>void 타입으로 바꾸는 것이 유용한 해결책이 될 수 있어요.

더 알아보기