TypeScript にて error: Type ‘xxxxx’ is not assignable to type ‘xxxxx’. が出た時の対応

例えば下記のようなエラーが出た時の対応。
型を確定させないと出るエラー。

error: Type 'T' is not assignable to type 'string'.
error: Type 'object | null' is not assignable to type 'object'.
  Type 'null' is not assignable to type 'object'.
error: Type 'string | null' is not assignable to type 'string'.
  Type 'null' is not assignable to type 'string'.
error: Element implicitly has an 'any' type because index expression is not of type 'number'.
error: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Fruit'.
  No index signature with a parameter of type 'string' was found on type 'typeof Fruit'.
error: Property 'append' does not exist on type 'U'.
error: Argument of type 'unknown' is not assignable to parameter of type 'string'.

環境

  • TypeScript v5

型ガードする

その1: null チェック

// error: Type 'string | null' is not assignable to type 'string'.
//   Type 'null' is not assignable to type 'string'.
function sample(args: string | null): string {
	return args
}

function sample(args: string | null): string {
	if (args == null) return ""
	return args
}

その2: typeof

// error: Type 'T' is not assignable to type 'string'.
function sample<T>(args: T): string {
	return args
}

function sample<T>(args: T): string {
	return (typeof args == "string") ? args : ""
}

その3: instanceof

// error: Property 'append' does not exist on type 'U'.
function sample<T, U>(params: T, webApi: U): U {
	const query: object = params && typeof params == "object" ? params : {}
	for (const [key, value] of Object.entries(query)) {
		if (Array.isArray(value)) {
			for (const [_, v] of value.entries()) {
				webApi.append(key, v)
			}
			continue
		}
		webApi.append(key, value)
	}
	return webApi
}

sample<object, URLSearchParams>({ test: "aaaa"}, new URLSearchParams()).toString()

function sample<T, U>(params: T, webApi: U): U {
	const query: object = params && typeof params == "object" ? params : {}
	for (const [key, value] of Object.entries(query)) {
		if (Array.isArray(value)) {
			for (const [_, v] of value.entries()) {
				if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
					webApi.append(key, v)
				}
			}
			continue
		}
		if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
			webApi.append(key, value)
		}
	}
	return webApi
}

sample<object, URLSearchParams>({ test: "aaaa"}, new URLSearchParams()).toString()

その4: as keyof typeof

例えばこんな enum

enum Sample1 {
	Apple,
	Lemon,
	Orange,
}

enum Sample2 {
	Apple = "apple",
	Lemon = "lemon",
	Orange = "orange",
}
// error: Element implicitly has an 'any' type because index expression is not of type 'number'.
function sample1(): number {
	let res = 0
	for (const key of Object.keys(Sample1).values()) {
		res = Sample1[key]
	}
	return res
}

// error: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Sample2'.
//   No index signature with a parameter of type 'string' was found on type 'typeof Sample2'.
function sample2(): string {
	let res = ""
	for (const key of Object.keys(Sample2).values()) {
		res = Sample2[key]
	}
	return res
}

function sample1(): number {
	let res = 0
	for (const key of Object.keys(Sample1).values()) {
		res = Sample1[key as keyof typeof Sample1]
	}
	return res
}

function sample2(): string {
	let res = ""
	for (const key of Object.keys(Sample2).values()) {
		res = Sample2[key as keyof typeof Sample2]
	}
	return res
}

その5: Array.isArray() など

// error: Argument of type 'unknown' is not assignable to parameter of type 'string'.
function sample<T, U>(params: T, webApi: U): U {
	const query: object = params && typeof params == "object" ? params : {}
	for (const [key, value] of Object.entries(query)) {
		let foundArray = false
		for (const [_, v] of Object.entries(value)) {
			if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
				webApi.append(key, v)
				foundArray = true
			}
		}
		if (foundArray) {
			continue
		}
		if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
			webApi.append(key, value)
		}
	}
	return webApi
}

function sample<T, U>(params: T, webApi: U): U {
	const query: object = params && typeof params == "object" ? params : {}
	for (const [key, value] of Object.entries(query)) {
		if (Array.isArray(value)) {
			for (const [_, v] of value.entries()) {
				if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
					webApi.append(key, v)
				}
			}
			continue
		}
		if (webApi instanceof URLSearchParams || webApi instanceof FormData) {
			webApi.append(key, value)
		}
	}
	return webApi
}