ReScript in Korean

타입

원문

타입(Type)은 리스크립트의 꽃이라 할 수 있습니다! 타입은

  • 강력합니다. 리스크립트의 타입은 다른 타입으로 바뀌지 않습니다. 보통의 자바스크립트에서는 코드가 진행(런타임)될 때 변수의 타입이 바뀌기도 합니다. 예를 들어, Number타입의 변수가 가끔 String타입의 변수로 바뀌기도 합니다. 이것은 코드를 읽거나 디버깅을 할때 코드를 더욱 이해하기 어렵기 하기 때문에 하나의 반기능(anti-feature)이라 할 수 있습니다.
  • 정적입니다. 리스크립트의 타입들은 컴파일 후에 사라지고 타입이 필요없는 런타임 단계에서는 그 정보들이 남아있지 않습니다. 사용된 타입들이 퍼포먼스에 악영향을 끼치지 않는다는 것이죠. 또한, 리스크립트는 모든 정보들(특히 모든 타입 오류들)을 컴파일 중에 알려줍니다. 버그를 빨리 잡아보세요!
  • 명확합니다. 자바스크립트로 컴파일되는 다른 타입 언어와 비교할 때 가장 큰 차별화 요소로, 리스크립트의 타입 시스템은 절대 틀리지 않습니다. 대부분의 타입 시스템은 값의 타입을 추측하고, 때로는 잘못된 유형을 표시합니다. 그러나 리스크립트는 부정확한 타입 시스템이 기대 불일치에서 발생하는 위험이라 믿기 때문에 절대 틀리지 않습니다.
  • 빠릅니다. 많은 개발자들이 자신들의 프로젝트의 타입 검사에 투자되는 시간들을 과소평가합니다. 리스크립트의 타입 검사기는 가장 빠른 검사기 중 하나입니다.
  • 유추됩니다. 타입을 하나하나 쓸 필요가 없습니다! 리스크립트는 변수의 값에서 타입을 유추할 수 있습니다. 네, 리스크립트가 여러분의 파일의 타입을 모두 유추할 수 있다는게 믿기지 않겠지만, 틀리거나 직접 쓰지않고도 빠르게 유추할 수 있습니다. 리스크립트의 세계에 오신걸 환영합니다 😆

이제 리스크립트 타입 시스템을 하나하나 알려 드리겠습니다.

추론(Inference)

다음 let 바인딩은 어떠한 타입도 작성하지 않았습니다.

let score = 10
let add = (a, b) => a + b
var score = 10;
function add(a, b) {
return (a + b) | 0;
}

리스크립트는 score 가 가지고 있는 값 10을 토대로 int라는 것을 알고 있습니다. 이것을 추론이라고 합니다. 이와 같이, 리스크립트는 add 함수가 정수들을 사용하는 + 연산자를 토대로 두개의 int를 받고 int를 반환하는 것으로 추론할 수 있습니다.

타입 어노테이션(Type Annotation)

위와 같이 타입들이 추론되지만서도, 여러분은 직접 타입을 유동적으로 쓸 수도 있습니다. 이걸 리스크립트에서는 값에 어노테이션(Annotation)을 쓴다고 하죠.

let score: int = 10
var score = 10;

만약 score의 타입 어노테이션이 리스크립트가 유추한 타입과 일치하지 않는 경우, 리스크립트는 컴파일 시점에 에러를 보여줄 것입니다. 리스크립트는 다른 많은 언어들과는 달리, 여러분의 타입 어노테이션이 맞을 것이라고 가볍게 넘기지 않을 것 입니다. 여러분은 아래와 같이 어떤 표현이든 괄호에 넣고 어노테이션을 넣을 수 있습니다.

let myInt = 5
let myInt: int = 5
let myInt = (5: int) + (4: int)
let add = (x: int, y: int) : int => x + y
let drawCircle = (~radius as r: int): circleType => /* code here */
var myInt = 9;
function add(x, y) {
return (x + y) | 0;
}
function drawCircle(r) {
/* code here */
}

참고: 마지막 줄의 (~radius as r: int)은 이름있는 인자입니다. 자세한 내용은 함수 페이지 에서 확인하세요.

타입의 별칭(Type alias)

여러분은 타입에 다른 이름을 부여할수 있습니다. 이 예시들은 같은 뜻입니다.

type scoreType = int
let x: scoreType = 10
var x = 10;

타입 매개변수(A.k.a Generic)

타입들은 매개변수를 받을 수 있습니다. 다른 언어에서는 Generics라고 하죠. 매개변수들의 이름은 '으로 시작해야 합니다.

중복을 제거하기 위해 매개변수화 한 타입을 사용한 예제입니다.

사용 전:

/* this is a tuple of 3 items, explained next */
type intCoordinates = (int, int, int)
type floatCoordinates = (float, float, float)
let a: intCoordinates = (10, 20, 20)
let b: floatCoordinates = (10.5, 20.5, 20.5)
var a = [10, 20, 20];
var b = [10.5, 20.5, 20.5];

사용 후:

type coordinates<'a> = ('a, 'a, 'a)
let a: coordinates<int> = (10, 20, 20)
let b: coordinates<float> = (10.5, 20.5, 20.5)
var a = [10, 20, 20];
var b = [10.5, 20.5, 20.5];

위의 코드는 설명을 위해 고안된 예일뿐입니다. 타입이 유추되었으므로 다음과 같이 작성할 수 있습니다.

let buddy = (10, 20, 20)
var buddy = [10, 20, 20];

타입 시스템은 이것이 (int, int, int)라고 추론합니다. 다른 어떤 것도 쓰여질 필요가 없습니다.

타입 인자는 여러 위치에 나타납니다. 리스크립트의 array<'a> 타입은 타입 매개변수는 필요한 유형입니다.

/* inferred as `array<string>` */
let greetings = ["hello", "world", "how are you"]
/* inferred as `array<string>` */
var greetings = ['hello', 'world', 'how are you'];

만약 타입 매개변수를 허용하지 않는다면 표준 라이브러리는 arrayOfString,arrayOfInt,arrayOfTuplesOfInt 등의 타입을 정의해야합니다. 아주 지루한 일이죠.

타입은 많은 인자를 받을 수 있고 구성할 수 있습니다.

type result<'a, 'b> =
| Ok('a)
| Error('b)
type myPayload = {data: string}
type myPayloadResults<'errorType> = array<result<myPayload, 'errorType>>
let payloadResults: myPayloadResults<string> = [
Ok({data: "hi"}),
Ok({data: "bye"}),
Error("Something wrong happened!")
]
var payloadResults = [
{
TAG: /* Ok */ 0,
_0: { data: 'hi' },
},
{
TAG: /* Ok */ 0,
_0: { data: 'bye' },
},
{
TAG: /* Error */ 1,
_0: 'Something wrong happened!',
},
];

재귀 타입(Recursive Types)

함수와 같이, 타입은 rec을 사용해 자기 자신을 참조할 수 있습니다.

type rec person = {
name: string,
friends: array<person>
}
// Empty output

상호적 재귀 타입(Mutually Recursive Types)

타입은 and 를 통해 상호적 재귀가 될 수 있습니다.

type rec student = {taughtBy: teacher}
and teacher = {students: array<student>}
// Empty output

타입 탈출구(Type Escape Hatch)

리스크립트 타입 시스템은 견고하고 암시적인 타입 변환과 같은 안전하지 않거나 값의 타입을 마구잡이로 예측하는 등의 위험을 허락하지 않습니다. 하지만, 실용적인 측면에서 리스크립트는 타입 시스템을 "속일 수"있는 하나의 탈출구를 제공합니다.

external myShadyConversion: myType1 => myType2 = "%identity"
// Empty output

이 선언은 myType1myType2로 바꿔줍니다. 이런 탈출구는 아래와 같이 사용할 수 있습니다.

external convertToFloat : int => float = "%identity"
let age = 10
let gpa = 2.1 +. convertToFloat(age)
var age = 10;
var gpa = 2.1 + 10;

절대 이 기능을 남용하지 마십시오. 기존의 지나치게 동적인 JS 코드의 작업이 필요할 때, 세련되게 사용하기 바랍니다.

더 자세한 내용은 여기서 확인하세요.

참고: @bs 어노테이션이 선행되지 않는 것으론 external이 유일합니다.