首页 > 解决方案 > 我可以使对象属性类型依赖于另一种属性类型吗?

问题描述

我有一个看起来像这样的对象:

interface AuthState {
  isSignedIn: boolean
  token?: string
  user?: User
}

user可以是未定义的,但仅当isSignedIn === false. 在应用程序中不可能有isSignedIn === true也没有用户对象。我希望能够强制执行并避免必须执行以下操作:

// If I don't check for `user`, TS will throw an error since it doesn't see any
// relation between the 2 properties
const userName = isSignedIn && user && user.name

标签: typescriptconditional-types

解决方案


如果我理解你的问题,这应该是你要找的。

interface FalseAuthState {
  isSignedIn: false;
}

interface TrueAuthState {
  isSignedIn: true;
  token: string;
  user: User;
}

type AuthState = FalseAuthState | TrueAuthState;

所以现在,如果你有一个像

// This does not throw an error because Typescript knows it's correct
const noAuth: AuthState = {
   isAuth: false
} 

// This will throw an error because Typescript demands a User and Token.
const yesAuth: AuthState = {
   isAuth: true
} 

// This will not throw an error.
const realAuth: AuthState = {
  isAuth: true,
  token: "ABCD123",
  user: new User()
} 

function printUser(auth: AuthState) {
  if (auth.isAuth) {
     console.log(auth.user); // Typescript knows there's supposed to be a user so there is no error
  }
}

function badPrintUser(auth: AuthState) {
   if (auth.isAuth === false) {
      console.log(auth.user); // Typescript will throw an error because there's no supposed to be a user here.
   }
}

在您的示例中,您检查的方式如下:

const userName = auth.isSignedIn && auth.user.name

或者

const userName = auth.isSignedIn ? auth.user.name : undefined;

不幸的是,您将无法从对象本身中删除属性并将其用于您的优势。如果你要这样做

const { isSignedIn, user } = (auth as TrueAuthState);
const userName = isSignedIn && user && user.name; // You still have to do this unless you really sure that the auth is a TrueAuthState

推荐阅读