docs(TechLog): 글감 56개를 기록으로 쓴다
주제 13개 · Case 28 · Concept 5 · Reference 15 · Question 4 · Decision 4. 계약의 노드마다 종류가 요구하는 칸을 채우고, 본문이 있는 두 종류에는 SSOT 가 이미 그려 둔 도식 셋(value-boundaries · decision-path-404 · topic-variant-model)을 tech-log-studio/ 로 옮겨 붙였다. 새로 그린 그림은 없다. 검사 셋 전부 통과한다. check_body.mjs 56 편 중 본문이 있는 33 편 PASS check_prose.mjs 56 편 error 0 check_evidence.mjs --repo 포함 문제 없음 verify-tech-log-tree.py 프로젝트 5 · error 0 · warn 0 인용한 코드블록은 전부 SSOT 에서 찾아 대조했다. check_evidence.mjs 가 본문의 각 줄과 source 앵커와 계약 제목을 다시 확인한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6955611439
commit
f6c825e858
+72
@@ -0,0 +1,72 @@
|
||||
---
|
||||
kind: CONCEPT
|
||||
slug: where-typescript-stops-checking
|
||||
title: TypeScript 가 검사를 놓아 주는 네 자리 — 메서드 매개변수의 bivariance · as 단언 · never 캐스트 · 검사 대상을 갖지 않은 tsconfig
|
||||
topic: what-the-compiler-lets-through
|
||||
topicName: 타입 검사가 통과시키는 곳
|
||||
project: TechLog
|
||||
status: 게시 전
|
||||
basisVersion: TypeScript 5.x · project references 로 나눈 여섯 프로젝트 구성 · 2026-09-02 시점의 tech-log-frontend
|
||||
sourceRevision: tech-log@2026-09-02
|
||||
source:
|
||||
- final/document.md#§6.6
|
||||
- final/document.md#§6.2
|
||||
- final/document.md#§6.3
|
||||
---
|
||||
|
||||
# TypeScript 가 검사를 놓아 주는 네 자리 — 메서드 매개변수의 bivariance · as 단언 · never 캐스트 · 검사 대상을 갖지 않은 tsconfig
|
||||
|
||||
「타입 검사가 통과했으니 반영됐다」는 판단이 이 저장소에서 네 번 틀렸다. 매번 다른 이유였다 — 메서드 매개변수의 bivariance, `as` 단언, `never` 로 받아 캐스팅하는 조립기, 그리고 검사할 파일을 갖지 않은 tsconfig 다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **구현이 종류를 좁게 적어도 넓은 포트를 만족했다**
|
||||
bivariance 가 통과시킨 사건이다.
|
||||
- **npx tsc --noEmit 이 한 파일도 검사하지 않고 성공했다**
|
||||
검사 대상이 없는 tsconfig 가 통과시킨 사건이다.
|
||||
- **공개 Reference 가 통째로 비어 있었다**
|
||||
`as` 단언이 통과시킨 사건이다.
|
||||
|
||||
## 본문
|
||||
|
||||
<!-- body:start -->
|
||||
|
||||
## 메서드 매개변수는 bivariant 다
|
||||
|
||||
포트가 네 값을 받는다고 선언하고 구현이 세 값만 적어도 두 시그니처는 호환된다고 판정된다. TypeScript 는 메서드 문법으로 쓴 매개변수를 bivariant 로 다룬다.
|
||||
|
||||
```ts
|
||||
deleteDocument(kind: "CASE" | "REFERENCE" | "QUESTION" | "CONCEPT", id: string): Promise<void>;
|
||||
```
|
||||
|
||||
구현이 이 시그니처를 만족한다고 통과해도, 실행할 때 네 번째 값이 어디로 가는지는 구현 안의 분기가 정한다.
|
||||
|
||||
같은 이유로 포트와 어댑터가 타입을 따로 들고 있으면 `satisfies` 도 한쪽이 좁아진 것을 잡지 못한다.
|
||||
|
||||
## as 단언은 이름을 묻지 않는다
|
||||
|
||||
```ts
|
||||
const summary = body.purposeSummary as string; // 계약에 그런 칸이 없다
|
||||
```
|
||||
|
||||
`as` 는 「이 값을 이 타입으로 다루겠다」는 선언이라, 그 이름이 응답 타입에 있는지 묻지 않는다. 실행하면 `undefined` 가 나온다.
|
||||
|
||||
모양이 다른 경우에는 더 나빠진다. 객체를 배열로 읽고 `.filter` 를 부르면 매핑이 통째로 터지는데, `as` 캐스트가 그 어긋남을 타입 검사에서 가린다.
|
||||
|
||||
## never 로 받으면 아무것도 요구하지 않는다
|
||||
|
||||
요청을 만드는 조립기가 입력을 `(input: never)` 로 받아 캐스팅하면, 계약에 인자를 더해도 컴파일러가 아무 말도 하지 않는다. 조립기가 손으로 나열한 질의 인자에 그 값이 없으면 요청에서 조용히 빠진다.
|
||||
|
||||
목록의 페이지 번호를 눌러도 쪽이 넘어가지 않던 것이 이 모양이었다. `page` 가 조립기의 목록에 없었다.
|
||||
|
||||
## 검사할 파일이 없는 tsconfig
|
||||
|
||||
루트 tsconfig 가 `"files": []` 에 project references 만 나열하면 `npx tsc --noEmit` 은 한 파일도 검사하지 않고 성공한다. references 를 따라가는 것은 별도 명령이다.
|
||||
|
||||
## 네 가지가 공통으로 하는 일
|
||||
|
||||
넷 다 「이 코드가 그 타입과 맞는가」라는 질문을 다른 질문으로 바꾼다. bivariance 는 시그니처 호환으로, `as` 는 작성자의 선언으로, `never` 는 검사 없음으로, 빈 tsconfig 는 대상 없음으로 바꾼다.
|
||||
|
||||
그래서 이 넷을 지난 통과는 「코드가 맞다」가 아니라 「검사가 그 질문을 하지 않았다」를 뜻한다.
|
||||
|
||||
<!-- body:end -->
|
||||
Reference in New Issue
Block a user