Загрузка…
Загрузка…
TypeScript · middle · сложность 6
Narrowing — TypeScript следует за runtime control flow (typeof, in, instanceof, truthiness, equality) и сужает широкий тип внутри ветки. User-defined type guard (x is Foo) упаковывает логику в функцию — но это ваше обещание, компилятор тело не верифицирует.
Control-flow analysis отслеживает самый узкий тип переменной в каждой точке. После проверки каст обычно не нужен.
Caveat guard'а: function isUser(x: unknown): x is User { return true; } скомпилируется и соврёт. Здесь снова пролезает runtime-дыра.
Нюансы операторов:
typeof: примитивы; typeof null === 'object'; для callable — typeof x === 'function'.instanceof: prototype chain; ломается между realms; не работает с interface (стёрт).in: сужение по наличию поля.0/'' — ловушка.== null — идиома для nullish.Assertion functions (asserts x is T) сужают через throw. Narrowing сбрасывается через closure/await для мутабельного let.
// Built-in narrowing follows control flow — no casts needed
function fmt(x: string | number | null) {
if (x == null) return 'none'; // narrows out null AND undefined
if (typeof x === 'string') return x.trim(); // x: string here
return x.toFixed(2); // x: number here
}
// ❌ typeof object includes null (the JS legacy bug)
function bad(x: object | null) {
if (typeof x === 'object') x.valueOf(); // ❌ x could still be null!
}
// ✅ user-defined type guard — reusable narrowing (but UNVERIFIED)
function isString(x: unknown): x is string {
return typeof x === 'string'; // TS trusts this return; it does NOT check it
}
// ✅ assertion function — narrows by throwing
function assert(cond: unknown, msg: string): asserts cond {
if (!cond) throw new Error(msg);
}
function use(x: string | undefined) {
assert(x, 'missing'); // after this line, x is string
return x.length;
}// ❌ A lying guard type-checks — the runtime hole
function isUser(x: unknown): x is { id: number } { return true; }
const u = JSON.parse('null');
if (isUser(u)) u.id; // compiles; crashes — the guard body was a lieNarrowing — анализ потока; custom guards мощны, но непроверяемы. Не лгите в x is T, и помните про сброс сужения через async/closures.