TypeScript是否支持原生限制对象仅包含指定类型定义的属性?
Great question! TypeScript’s default structural typing means it allows objects with extra properties as long as they have all the required ones (which is why your getAll() function doesn’t throw an error right now). But if you want to strictly enforce that objects only contain the properties defined in their type, there are a few native TypeScript approaches you can use:
1. Use satisfies (TypeScript 4.9+) for Compile-Time Checks
The satisfies operator lets you validate that an object matches a type without widening it, and it will flag any extra properties. You can use it when mapping your User objects to GetAllUserData:
async getAll(): Promise<GetAllUserData[]> { const users = await dbQuery(); // Returns User[] return users.map(user => { // Extract only the properties you need const filteredUser = { id: user.id }; // Ensure filteredUser exactly matches GetAllUserData return filteredUser satisfies GetAllUserData; }); }
If you accidentally include an extra property (like name) in filteredUser, TypeScript will throw a compile-time error immediately.
2. Exact Type Utility for Older TypeScript Versions
If you’re using a version before 4.9, you can create a utility type that explicitly disallows extra properties by combining a mapped type with a never index signature:
// Utility type to block extra properties type Exact<T> = T & { [K: string]: never }; async getAll(): Promise<GetAllUserData[]> { const users = await dbQuery(); return users.map(user => { const filteredUser = { id: user.id }; // Assert that filteredUser has no extra properties return filteredUser as Exact<GetAllUserData>; }); }
Any extra property in filteredUser will conflict with the string: never signature, triggering a compile error.
3. Runtime Validation (For Extra Safety)
TypeScript is a compile-time only tool, so if you need to guarantee that your objects don’t have extra properties at runtime (e.g., if dbQuery() might return unexpected fields), you can add a runtime check function:
// Runtime function to verify an object only has allowed keys function hasOnlyAllowedKeys<T extends object>(obj: unknown, allowedKeys: (keyof T)[]): obj is T { if (typeof obj !== 'object' || obj === null) return false; const actualKeys = Object.keys(obj); return actualKeys.every(key => allowedKeys.includes(key as keyof T)); } async getAll(): Promise<GetAllUserData[]> { const users = await dbQuery(); const result = users.map(user => ({ id: user.id })); // Validate every object in the result if (!result.every(item => hasOnlyAllowedKeys(item, ['id']))) { throw new Error("Returned objects contain unexpected properties"); } return result; }
This adds an extra layer of safety to catch any unexpected properties that might slip through at runtime.
Key Note
TypeScript’s structural typing is intentional—it’s designed to be flexible. But these methods let you opt into stricter checks when you need them. The satisfies operator is the cleanest modern approach, while runtime checks are best for critical code where you can’t trust the input source.
内容的提问来源于stack exchange,提问作者Valera

