"클래스 자체가 가진 것과, 각 인스턴스가 가진 것을 먼저 갈라 놓자."
정적 쪽과 인스턴스 쪽
static 멤버는 개별 객체가 아니라 클래스 생성자에 붙어. Id 클래스의 정적 next는 모든 인스턴스가 공유하고, 인스턴스 필드 value는 객체마다 달라.
이 구분 때문에 new C()로 만드는 객체의 계약과 C.create() 같은 팩터리의 계약을 같은 인터페이스로 표현할 수 없는 경우가 있어. 생성자를 인자로 받는 함수라면 new (...args: A) => T 같은 생성 시그니처를 따로 써야 하지.
다형적인 this 타입
메서드 반환 타입에 this를 쓰면 하위 클래스에서 호출했을 때 하위 클래스 타입이 유지돼. 빌더가 setName(...): this를 반환하면 체이닝 중에 파생 클래스의 추가 메서드도 잃지 않아. 부모 클래스 이름을 반환 타입으로 고정하는 것보다 유연하지.
정적 팩터리에서는 static create(): Counter { return new this() }처럼 호출한 클래스 자체를 가리키는 this로 인스턴스를 만들 수 있어. 하위 클래스가 이 메서드를 호출하면 부모가 아니라 하위 클래스 생성자가 선택돼.
static은 클래스 객체의 상태, 인스턴스 멤버는 만들어진 객체의 상태야. 두 세계를 구분하면 생성자 타입과 this 관련 오류가 훨씬 읽기 쉬워져.