TypeScript:函数的通用类型将参数视为 "any",尽管另有声明

TypeScript: Generic types for functions treat parameters as "any" despite declaring them otherwise

使用 TypeScript 4.4.3,我希望能够将函数参数显式键入 return 为泛型的函数。 TypeScript 忽略了使用泛型的函数的参数类型,将它们视为 any.

下面是一个人为的例子(不是一个非常有用的函数),如果它被粘贴到 TS Playground 中,它将在输入参数上显示一个警告,说明它是“任何”类型...

type GenericResult = <T>(input: number) => T
export const returnWhatever: GenericResult = <T>(input) => <T> input

是否应该忽略第一行中定义的参数类型?

我的实际用例是这样的...

import type { QueryResult } from 'pg'
import pg from 'pg'

const pgNativePool = new pg.native.Pool({
  max: 10,
  connectionString: import.meta.env.VITE_DATABASE_URL,
  ssl: {
    rejectUnauthorized: false
  }
})

type AcceptableParams = number | string | boolean

type PostgresQueryResult = (sql: string, params?: AcceptableParams[]) => Promise<QueryResult<any>>
const query: PostgresQueryResult = (sql, params?) => pgNativePool.query(sql, params)

type GetOneResult = <T>(sql: string, id: number | string) => Promise<T>
const getOne: GetOneResult = async <T>(sql, id) => {
  const { rows } = await query(sql, [id])
  return <T> rows[0]
}

const user = await getOne<User>('SELECT * FROM users WHERE id = ;', 33)
// returns a User

在上面的示例中,sql 参数必须始终是字符串,id 可以是数字或字符串。

虽然函数的 return 值的类型是在调用函数的位置确定的,但能够为该函数键入参数似乎仍然是个好主意,因为该部分是已知的。

可能吗?

根据对话更新示例

type GenericResult = <T = number>(input: T) => T;
export const returnWhatever: GenericResult = (input) => input;

returnWhatever<string>("1");
returnWhatever(1);
returnWhatever<number>("1"); // will error

Typescript 感到困惑,因为它认为您正在覆盖函数参数的类型。我认为你这样做是因为你想重新指定泛型,但你不必这样做,因为你已经在箭头函数的类型上输入了 this。这应该足够了:

type GetManyResults = <T>(sql: string) => Promise<{ body: T[]; }>
export const getMany: GetManyResults = async (sql) => {
  const { rows } = await query(sql)
  return {
    body: rows
  }
}

Microsoft 的建议是在通用函数的定义中显式键入参数,就像我在下面对下面的 getOne 函数所做的那样。这“感觉”不对,因为我定义了两次参数类型,但无论如何...

import type { QueryResult } from 'pg'
import pg from 'pg'

const pgNativePool = new pg.native.Pool({
  max: 10,
  connectionString: import.meta.env.VITE_DATABASE_URL,
  ssl: {
    rejectUnauthorized: false
  }
})

type AcceptableParams = number | string | boolean

type PostgresQueryResult = (sql: string, params?: AcceptableParams[]) => Promise<QueryResult<any>>
const query: PostgresQueryResult = (sql, params?) => pgNativePool.query(sql, params)

type GetOneResult = <T>(sql: string, id: number | string) => Promise<T>
const getOne: GetOneResult = async <T>(sql: string, id: number | string) => {
  const { rows } = await query(sql, [id])
  return <T> rows[0]
}

const user = await getOne<User>('SELECT * FROM users WHERE id = ;', 33)
// returns a User