如何在文字对象上正确使用接口

Posted

技术标签:

【中文标题】如何在文字对象上正确使用接口【英文标题】:How to correctly use an interface on a literal object 【发布时间】:2020-11-30 19:49:24 【问题描述】:

我在打字稿上有点吃力。假设你有一个文字对象,它的值是用扩展运算符分配的:

const defaultState = () => 
  return 
    profile: 
      id: '',
      displayName: '',
      givenName: '',
      surName: '',
    ,
  


const state = reactive(defaultState())
const response = await getGraphprofile()
state.profile =  ...defaultState().profile, ...response.data 

在更新类型库@microsoft/microsoft-graph-types 后,抛出以下 TS 错误:

TS2322: Type ' accountEnabled?: Maybe<boolean>; ageGroup?: string | null | undefined; assignedLicenses?: MicrosoftGraph.AssignedLicense[] | undefined; assignedPlans?: MicrosoftGraph.AssignedPlan[] | undefined; ... 102 more ...; surName: string; ' is not assignable to type ' id: string; displayName: string; givenName: string; surName: string; jobTitle: string; mail: string; mobilePhone: string; officeLocation: string; businessPhones: string[]; preferredLanguage: string; userPrincipalName: string; '.
  Types of property 'displayName' are incompatible.
    Type 'string | null' is not assignable to type 'string'.
      Type 'null' is not assignable to type 'string'.

尝试像this answer 那样在文字对象上设置接口MicrosoftGraph.User 并没有解决它,因为我一定是语法有问题:

import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'

const defaultState = () => 
  return 
    profile: MicrosoftGraph.User = 
      id: '',
      displayName: '',
      givenName: '',
      surName: '',
    ,
  

这会引发下面的 TS 错误,但User 接口肯定存在并且在函数getGraphProfile 中正确使用。

TS2339:“类型导入”类型上不存在属性“用户”(“T:/Test/Brecht/Node/prod/hip-frontend/node_modules/@microsoft/microsoft-graph-types/microsoft-graph”) '。

额外代码:

import config from 'src/app-config.json'
import axios,  AxiosRequestConfig  from 'axios'
import  getToken  from 'src/services/auth/authService'
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'

const callGraph = <T>(
  url: string,
  token: string,
  axiosConfig?: AxiosRequestConfig
) => 
  const params: AxiosRequestConfig = 
    method: 'GET',
    url: url,
    headers:  Authorization: `Bearer $token` ,
  
  return axios.request<T>( ...params, ...axiosConfig )


const getGraphDetails = async <T>(
  uri: string,
  scopes: string[],
  axiosConfig?: AxiosRequestConfig
) => 
  try 
    const response = await getToken(scopes)
    if (response && response.accessToken) 
      return callGraph<T>(uri, response.accessToken, axiosConfig)
     else 
      throw new Error('We could not get a token because of page redirect')
    
   catch (error) 
    throw new Error(`We could not get a token: $error`)
  


export const getGraphProfile = async () => 
  try 
    return await getGraphDetails<MicrosoftGraph.User>(
      config.resources.msGraphProfile.uri,
      config.resources.msGraphProfile.scopes
    )
   catch (error) 
    throw new Error(`Failed retrieving the graph profile: $error`)
  

displayName 属性保存为string | null 的正确方法是什么?

【问题讨论】:

如果在defaultState 中分配displayName null 会发生什么? 试过了,它会抛出Type 'string | null' is not assignable to type 'null' 我们聊天here 【参考方案1】:

问题在于隐式类型。

const state = reactive(defaultState())

State 在这里定义为没有显式类型并分配为reactive(defaultState)。这意味着它的类型为defaultState

const defaultState = () => 
  return 
    profile: 
      id: '',
      displayName: '',
      givenName: '',
      surName: '',
    ,
  

defaultState 这里没有类型,因此具有返回对象的隐式类型。

所以当我们给state赋值时

state.profile =  ...defaultState().profile, ...response.data 

其中response.data 被类型化为MicrosoftGraph.User 其中displayName: string | null

所以state.profile.displayName 的类型是string 但是response.data.displayName 的类型是string | null 从而导致我们的TS 错误。

解决办法

我们所要做的就是更好的类型安全defaultState

const defaultState = () => 
  return 
    profile: 
      id: '',
      displayName: '',
      givenName: '',
      surName: '',
    ,
   as  profile: MicrosoftGraph.User ,

【讨论】:

以上是关于如何在文字对象上正确使用接口的主要内容,如果未能解决你的问题,请参考以下文章

如何正确检查对象是不是实现接口

在windows中,如何使用cmd命令行窗口正确显示编码为utf-8格式的文字

如何在 Apollo Server 中正确键入上下文对象?

如何使cmd窗口正确显示utf-8编码的文字

如何使 TypeScript 字符串枚举适用于字符串文字并正确进行类型推断

如何正确克隆 JavaScript 对象?