![](/img/trans.png)
[英]ESLint: Unsafe assignment of an `any` and Unsafe call of an `any` typed value
[英]@typescript-eslint/no-unsafe-assignment: Unsafe assignment of an any value
考慮以下代碼:
const defaultState = () => {
return {
profile: {
id: '',
displayName: '',
givenName: '',
},
photo: '',
}
}
const state = reactive(defaultState())
export const setGraphProfile = async () => {
const response = await getGraphProfile()
state.profile = { ...defaultState().profile, ...response.data }
}
這會生成 ESLint 警告:
@typescript-eslint/no-unsafe-assignment:任何值的不安全賦值。
這意味着response.data
中的屬性可能與profile
中的屬性不匹配。 getGraphProfile
的返回是Promise<AxiosResponse<any>>
。 當然,通過簡單地忽略它很容易擺脫這個 ESLint 警告:
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
state.profile = { ...defaultState().profile, ...response.data }
getGraphProfile
中的數據使其匹配? 因為可以創建一個 TS interface
,但這只會使用 object defaultState().profile
創建重復的代碼const callGraph = (
url: string,
token: string,
axiosConfig?: AxiosRequestConfig
) => {
const params: AxiosRequestConfig = {
method: 'GET',
url: url,
headers: { Authorization: `Bearer ${token}` },
}
return axios({ ...params, ...axiosConfig })
}
const getGraphDetails = async (
uri: string,
scopes: string[],
axiosConfig?: AxiosRequestConfig
) => {
try {
const response = await getToken(scopes)
if (response && response.accessToken) {
return callGraph(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(
config.resources.msGraphProfile.uri,
config.resources.msGraphProfile.scopes
)
} catch (error) {
throw new Error(`Failed retrieving the graph profile: ${error}`)
}
}
export const getGraphPhoto = async () => {
try {
const response = await getGraphDetails(
config.resources.msGraphPhoto.uri,
config.resources.msGraphPhoto.scopes,
{ responseType: 'arraybuffer' }
)
if (!(response && response.data)) {
return ''
}
const imageBase64 = new Buffer(response.data, 'binary').toString('base64')
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return `data:${response.headers['content-type']};base64, ${imageBase64}`
} catch (error) {
throw new Error(`Failed retrieving the graph photo: ${error}`)
}
}
TypeScript 不會產生警告,只會產生錯誤。 就 TS 而言, any
分配都是有效的。 這就是 linter 提供額外支持的地方。
幸運的是,您不需要復制您的界面。 使用 TypeScript 的 ReturnType 在defaultState
方法中獲取profile
ReturnType
的類型:
type IProfile = ReturnType<typeof defaultState>["profile"]
上述行利用了 3 個出色的 TypeScript 特性:
ReturnType
推斷 function 返回的類型typeof
從 object 實例推斷接口["profile"]
獲取接口某個屬性的類型現在,讓您的callGraph
function 通用:
function 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 })
}
並在您的getGraphDetails
function 中更新callGraph
調用:
...
if (response && response.accessToken) {
return callGraph<IProfile>(uri, response.accessToken, axiosConfig)
}
...
現在您的圖形調用已正確鍵入,您不必復制配置文件定義; 相反,您使用 TypeScript 出色的類型推斷技術從 function 的返回類型中“讀取您的接口”。
以相反的順序回答您的問題:
為什么 TypeScript 對此代碼沒有問題,但 linter 有問題? 兩者都不需要對齊嗎?
在 Typescript 中,類型為any
的東西可以分配給任何東西。 使用any
本質上會從該部分代碼中刪除類型安全性。 例如:
const foo: number = 'hello' as any // Typescript is fine with this
我想該 eslint 規則的重點是捕捉您可能不想將any
類型的東西實際分配給其他東西的地方。 老實說,鑒於存在編譯器選項noImplicitAny
,我不太確定為什么要使用該 linting 規則。
如何塑造 Promise getGraphProfile 中的數據使其匹配? 因為可以創建一個 TS 接口,但這只會使用 object defaultState().profile 創建重復的代碼
有幾種方法可以解決這個問題。 最簡單的方法可能是輸入getGraphDetails
的返回值:
type GraphDetailsPayload = {
id: string,
displayName: string,
givenName: string,
}
export const getGraphProfile = async (): Promise<GraphDetailsPayload> => {
...
}
但通常最好在盡可能低的級別鍵入數據,在這種情況下,這意味着callGraph
function:
const callGraph = (
url: string,
token: string,
axiosConfig?: AxiosRequestConfig
): Promise<GraphDetailsPayload> => {
const params: AxiosRequestConfig = {
method: 'GET',
url: url,
headers: { Authorization: `Bearer ${token}` },
}
return axios({ ...params, ...axiosConfig })
}
通過這樣做,現在callGraph
的返回值是類型化的,因此 TS 將知道getGraphDetails
和getGraphProfile
都返回相同的類型,因為它們最終只是通過 API 響應。
最后一個選項:我不使用 Axios,但我敢打賭它的 Typescript 定義會讓你這樣做:
const callGraph = (
url: string,
token: string,
axiosConfig?: AxiosRequestConfig
) => {
const params: AxiosRequestConfig = {
method: 'GET',
url: url,
headers: { Authorization: `Bearer ${token}` },
}
return axios<GraphDetailsPayload>({ ...params, ...axiosConfig })
}
我已經刪除了Promise<GraphDetailsPayload>
返回類型,而是通過尖括號將GraphDetailsPayload
類型“傳入”到axios
function 調用。 這是利用了一種叫做“泛型”的東西,它是像 TS 這樣的類型系統中最有趣和最復雜的部分。 你會在你使用的庫中經常遇到它們,並且你最終會開始編寫使用 generics 的函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.