언어 기초

타입

타입 추론과 타입 표기를 익힙니다. 경계마다 유니온, 함수 타입, 명목 데이터 가운데 알맞은 것을 고릅니다.

타입을 쓰면 이 경계에 어떤 값이 들어올 수 있는지를 프로그램을 실행하기 전에 검사할 수 있습니다. 초기값만 봐도 타입이 분명한 지역 값에는 대개 타입을 적지 않아도 됩니다. 입력과 결과, 도메인의 중요한 선택을 드러내고 싶을 때 타입을 적으세요.

하나의 프로그램에서 시작하기

다음 코드를 types.tpz로 저장합니다.

TOPAZ
type Stage = "draft" | "ready"

function describe(stage: Stage, checks: int) -> string {
    "{stage} after {checks} checks"
}

let checks = 3
let current: Stage = "ready"
let render: (Stage, int) -> string = describe

print(render(current, checks))

먼저 타입 경계를 검사합니다. 그다음 실행합니다.

BASH
topaz check types.tpz
topaz run types.tpz

결과는 다음과 같습니다.

출력
ready after 3 checks

결과에서 타입 읽어 내기

checks에는 타입 표기가 없습니다. 초기값이 정수라서 토파즈가 int로 추론합니다. current에는 타입을 적었습니다. 아무 string이나 받지 않고 Stage만 받겠다는 뜻입니다.

Stage"draft" | "ready"라는 리터럴 유니온에 붙인 투명한 별칭입니다. 두 값 가운데 하나만 허용하고 다른 문자열은 거부합니다. 별칭은 이런 선택지에 읽기 쉬운 이름을 붙여 줍니다. 다만 별도의 런타임 정체성을 만들지는 않습니다.

render에는 함수 타입이 쓰였습니다. (Stage, int) -> string은 “Stageint를 받아 string을 돌려주는 함수”라는 뜻입니다. 이름 있는 함수 describe가 바로 이 형태입니다. 그래서 바인딩에 저장했다가 호출할 수 있습니다.

기본 타입 이름은 소문자로 씁니다. int, float, bool, string, 그리고 유닛 타입 ()가 있습니다. 자주 쓰는 컨테이너는 Array<T>, Map<K, V>, Set<T>처럼 이름 있는 생성자로 씁니다. 예상할 수 있는 값의 부재는 Option<T>로 나타냅니다. 복구할 수 있는 실패는 Result<T, E>로 나타냅니다.

의도에 맞는 형태 고르기

필요한 것권장 형태이유
타입이 분명한 지역 값타입 추론초기값만으로도 타입이 잘 드러납니다.
공개 입력·결과 또는 중요한 지역 경계타입 표기검사기와 독자가 의도한 계약을 바로 알 수 있습니다.
정해진 여러 대안 가운데 하나유니온 또는 리터럴 유니온 별칭허용되는 대안이 코드에 그대로 나타납니다.
나중에 호출할 수 있는 값(int) -> bool 같은 함수 타입매개변수와 결과 타입이 함수 값과 함께 유지됩니다.
도메인 정체성, 필드, 이름 붙은 경우record, enum, newtype내부 모양이 비슷해도 서로 다른 타입으로 남습니다.

type 별칭은 표현을 읽기 쉽게 만들어 줍니다. 하지만 원래 타입과 구분되는 정체성은 만들지 않습니다. 모양이 비슷한 두 값을 섞는 일이 실제 오류라면 명목 데이터를 고르세요. 레코드와 명목 데이터에서 record, enum, newtype의 생성과 패턴을 비교할 수 있습니다.

빈 값에는 문맥 제공하기

어떤 값은 그 자체만으로 타입을 다 알려 주지 못합니다. 빈 배열에는 원소 타입이 없습니다. None만 봐서는 어떤 타입의 값이 없다는 뜻인지 알 수 없습니다. 이럴 때는 타입 표기, 함수 매개변수, 선언된 결과 타입 같은 주변 문맥을 주세요.

let names: Array<string> = []
let selected: Option<int> = None

여기서는 올바른 형태만 보여 주려고 텍스트로 적었습니다. 이 페이지에서 실제로 검증하는 프로그램은 위의 실행 예제입니다.

흔한 실수: 대상 언어의 타입 표기 가져오기

토파즈 컬렉션 타입은 Array<T>, Map<K, V>, Set<T>로 씁니다. 함수 타입은 매개변수 타입을 괄호로 묶습니다. 그 뒤에 ->를 쓰고 결과 타입을 적습니다. 이 표기를 일관되게 써야 검사기와 생성 대상이 같은 소스 계약을 공유합니다.

정확한 한계

  • intfloat 사이에는 암묵적 변환이 없습니다.
  • 제네릭 타입 매개변수는 무공변입니다. 내용이 비슷하다는 이유만으로 서로 다른 타입 인수가 호환되지는 않습니다.
  • 제네릭 제약은 이름 있는 함수의 타입 매개변수에만 붙습니다. 허용되는 1계층 형태는 함수와 제네릭에서 설명합니다.
  • 재귀 타입 별칭, 분산(variance) 표기, 고위 다형성, 더 넓은 리플렉션은 아직 지원하지 않습니다.
  • 문맥을 줘도 타입 매개변수가 정해지지 않는 빈 제네릭 값이 있습니다. 이런 값은 실행 중에 추측하지 않고 정적 오류로 거부합니다.

타입 추론, 타입 표기, 가변성이 아직 낯설다면 값과 함수를 다시 살펴보세요. 값의 부재와 실패를 구분하고 싶다면 Null·Option·결과·실행 오류로 이어가세요.