mcpField
T
type-value-space

type-value-space

github.com/marius-townhouse开发643 次安装38 周前更新
代码仓库

关于 type-value-space

面向 TypeScript 开发者的技能,帮助区分类型空间与值空间中的符号,并说明上下文如何改变符号含义,包括 `typeof` 的不同作用。

主要功能

  1. 01区分类型空间与值空间
  2. 02根据上下文判断符号含义
  3. 03比较类型级与运行时 `typeof`
  4. 04理解类与接口的区别

适用场景

  1. 01排查不能作为值使用的符号
  2. 02用 `typeof` 获取类型
  3. 03避免解构参数中的类型标注错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill type-value-space

安装后在 Claude Code 中输入/type-value-space确认已加载。

详细介绍

了解如何判断符号属于类型空间还是值空间

概述

TypeScript 中的每个符号都存在于类型空间、值空间,或两者兼有。

同一个名称在不同上下文中可能指代完全不同的内容。理解这一区别对于正确阅读 TypeScript 代码至关重要。

何时使用此技能

  • 调试令人困惑的类型错误
  • 理解类与接口的行为差异
  • 正确使用 typeof
  • 使用类型注解进行解构
  • 理解枚举的行为

铁律

ALWAYS determine whether you're in type space or value space before interpreting a symbol.

请记住:

  • 类型会在运行时被擦除(使用 TypeScript Playground 验证)
  • 类会同时引入类型和值
  • typeof 在两个空间中的含义不同
  • 解构语法与类型注解语法不同

识别:相同名称,不同含义

// Same name, different entities!
interface Cylinder {
  radius: number;
  height: number;
}
const Cylinder = (radius: number, height: number) => ({ radius, height });

// This refers to the VALUE (function), not the TYPE (interface)
if (shape instanceof Cylinder) {
  // instanceof is a runtime operator - uses value space
}

两个空间

类型空间(运行时会被擦除)
type StringAlias = string;     // Type alias
interface Person { name: string; }  // Interface
type T = typeof myVar;         // Type-level typeof
值空间(运行时存在)
const x = 123;                 // Variable
function add(a, b) { return a + b; }  // Function
const t = typeof myVar;        // Runtime typeof (returns string)
两个空间兼有(class 和 enum)
class MyClass {
  value: number = 0;
}

// As a type: describes the shape of instances
const instance: MyClass = new MyClass();

// As a value: the constructor function
const ctor = MyClass;  // typeof ctor is typeof MyClass

上下文决定所属空间

在 : 或 as 后面 = 类型空间
const alice: Person = { name: 'Alice' };
//           ^^^^^^ Type space

const bob = someValue as Person;
//                       ^^^^^^ Type space
在 = 后面 = 值空间
const x = Person;  // Value space (error if Person is only a type)
函数签名会交替使用
function email(to: Person, subject: string, body: string): Response {
//             ^^          ^^^^^^^          ^^^^           ^^^^^^^^ Types
//       ^^^^^^^ ^^        ^^^^^^^ ^^^^^^   ^^^^ ^^^^              Values
}

typeof:在两个空间中的含义不同

类型空间中的 typeof
const person = { name: 'Alice', age: 30 };

type PersonType = typeof person;
//   ^? type PersonType = { name: string; age: number }

// Gets the TypeScript type of a value
值空间中的 typeof
const person = { name: 'Alice', age: 30 };

const t = typeof person;  // "object"
// JavaScript's runtime typeof - only 8 possible values:
// "string", "number", "boolean", "undefined", 
// "object", "function", "symbol", "bigint"

其他具有双重含义的结构

结构类型空间值空间
typeof值的 TypeScript 类型JS 运行时类型(8 种选项)
thisthis 的类型JS this 关键字
&、|交叉类型、联合类型按位与、或
constas const 上下文变量声明
extends子类型/约束子类
in映射类型for...in 循环
!非空断言逻辑非

属性访问:[] 与 .

interface Person {
  first: string;
  last: string;
}

// Value space: both work
const name1 = person['first'];
const name2 = person.first;

// Type space: ONLY brackets work
type First = Person['first'];     // OK: string
type First2 = Person.first;       // Error!

常见错误:使用类型进行解构

错误:在值位置使用类型名称
function email({
  to: Person,      // Error! 'Person' implicitly has 'any' type
  subject: string, // Error! 'string' implicitly has 'any' type
}) { }
// This creates variables named Person and string!
正确:将类型与解构分开
function email(
  { to, subject, body }: { to: Person; subject: string; body: string }
) { }
// Destructures values, then annotates the whole parameter

使用 TypeScript Playground

Playground 会显示哪些内容被擦除了:

interface Person { name: string; }  // Disappears in JS
type StringType = string;           // Disappears in JS

class MyClass { }                   // Stays (has runtime value)
const x = 42;                       // Stays (has runtime value)

如果某个符号在 JS 输出中消失了,它就只存在于类型空间。

抗压应对方案

1. “接口应该能用于 instanceof”

压力:“为什么 x instanceof MyInterface 不起作用?”

回应:instanceof 是运行时运算符。接口在运行时不存在。

**行动:**改用类型守卫或可辨识联合。

2. “typeof 应该能给出完整类型”

压力:“为什么 typeof x 只是 'object'?”

**回应:**你使用的是值空间中的 typeof。要获取 TypeScript 类型,请在类型注解中使用它。

**行动:**使用 type T = typeof x 获取完整的 TypeScript 类型。

危险信号——停下来重新考虑

  • 对接口或类型别名使用 instanceof
  • 期望运行时 typeof 能区分不同的对象形状
  • 解构后创建了意料之外的变量名
  • 类型错误提示“不能用作值”

常见借口(均不成立)

借口事实
“类和接口是一样的”类在运行时有值;接口没有
“typeof 在任何地方的用法都一样”它在类型空间和值空间中的含义完全不同
“我可以用类型名称进行解构”解构使用值空间;类型注解使用类型空间

快速参考

// Type space indicators:
type X = ...       // After 'type'
interface X { }    // After 'interface'
x: Type            // After ':'
as Type            // After 'as'

// Value space indicators:
const x = ...      // After '='
x instanceof Y     // instanceof operand
typeof x           // Without type annotation

// Both spaces:
class X { }        // Introduces type and value
enum X { }         // Introduces type and value

总结

上下文决定一个符号指代的是类型还是值。

同一个名称可能表示完全不同的内容。代码令人困惑时,先判断自己处于哪个空间。使用 TypeScript Playground 查看哪些内容会被擦除——那些就是类型空间中的内容。

参考资料

基于 Dan Vanderkam 所著的《Effective TypeScript》,第 8 条:了解如何判断符号属于类型空间还是值空间。

评论

支持 Markdown