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:
DongHyeonka
2026-09-07 15:29:33 +09:00
co-authored by Claude Opus 5
parent 6955611439
commit f6c825e858
62 changed files with 6381 additions and 186 deletions
@@ -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 -->