Flow,如何从混合类型转换为更具体的类型
Flow, how to type cast to a more specific type from mixed
express 的流类型 libdef 将 locals
定义为具有 mixed
个值的对象。
指定实际值类型会导致以下错误...应如何注释这些特定类型?
// From libdef
type Locals = {
[name: string]: mixed;
}
// Populated data
const locals: Locals = {
version: 1.2,
resources: {
a: "abc",
b: "def"
}
};
// Annotate the actual type
const version: number = locals.version; // Error: mixed is incompatible with number
const resources: {[string]: string} = locals.resources; // Error: mixed is incompatible with object type
看来这里唯一的方法就是添加 refinement 逻辑。
if (typeof locals.version === "number") {
const version: number = locals.version;
}
if (locals.resources instanceof Object) {
const resources: {[string]: string} = locals.resources;
}
请注意,您也可以只转换数据本身:
const version: number = Number(locals.version);
或者定义一个新的副本:
const resources: {[string]: string} = {...locals.resources};
一种方法是优化您收到的任何类型,直到它适合您正在寻找的形状。通常,我会制作一些基本的细化函数,然后使用它们来构建更大的细化。
(Try)
// From libdef
type Locals = {
[name: string]: mixed;
}
// Populated data
const locals: Locals = {
version: 1.2,
resources: {
a: "abc",
b: "def"
}
};
// The type you want
type MyLocals = {
version: number,
resources: {
// maybe this one is a map? idk
[string]: string
}
}
// Some basic refinement functions
const refineString = (x: mixed): string => {
if (typeof x === 'string') {
return x
}
throw new Error("Not a string")
}
const refineNumber = (x: mixed): number => {
if (typeof x === 'number') {
return x
}
throw new Error("Not a number")
}
const refineObj = (x: mixed): {[string]: mixed} => {
if (x instanceof Object) {
return x
}
throw new Error("Not an object")
}
// More type-specifc refinement functions
const refineResources = (x: mixed): $ElementType<MyLocals, 'resources'> => {
const anObj = refineObj(x)
return Object.keys(anObj)
.reduce((acc, k) => Object.assign(acc, { [k]: refineString(anObj[k]) }), {})
}
const refineMyLocals = (x: mixed): MyLocals => {
const {version, resources} = refineObj(x)
return {
version: refineNumber(version),
resources: refineResources(resources)
}
}
// Now use them to assert a type
const myLocals: MyLocals = refineMyLocals(locals)
const version: number = myLocals.version;
const resources: {[string]: string} = myLocals.resources;
或者,如果 libdef 在 flow-typed
文件夹中,只需进入那里并更改 libdef。它将使该类型特定于您的项目,但它可能是处理它的最有效方法,假设您不需要代码中其他地方的 [name: string]: mixed
类型。
express 的流类型 libdef 将 locals
定义为具有 mixed
个值的对象。
指定实际值类型会导致以下错误...应如何注释这些特定类型?
// From libdef
type Locals = {
[name: string]: mixed;
}
// Populated data
const locals: Locals = {
version: 1.2,
resources: {
a: "abc",
b: "def"
}
};
// Annotate the actual type
const version: number = locals.version; // Error: mixed is incompatible with number
const resources: {[string]: string} = locals.resources; // Error: mixed is incompatible with object type
看来这里唯一的方法就是添加 refinement 逻辑。
if (typeof locals.version === "number") {
const version: number = locals.version;
}
if (locals.resources instanceof Object) {
const resources: {[string]: string} = locals.resources;
}
请注意,您也可以只转换数据本身:
const version: number = Number(locals.version);
或者定义一个新的副本:
const resources: {[string]: string} = {...locals.resources};
一种方法是优化您收到的任何类型,直到它适合您正在寻找的形状。通常,我会制作一些基本的细化函数,然后使用它们来构建更大的细化。
(Try)
// From libdef
type Locals = {
[name: string]: mixed;
}
// Populated data
const locals: Locals = {
version: 1.2,
resources: {
a: "abc",
b: "def"
}
};
// The type you want
type MyLocals = {
version: number,
resources: {
// maybe this one is a map? idk
[string]: string
}
}
// Some basic refinement functions
const refineString = (x: mixed): string => {
if (typeof x === 'string') {
return x
}
throw new Error("Not a string")
}
const refineNumber = (x: mixed): number => {
if (typeof x === 'number') {
return x
}
throw new Error("Not a number")
}
const refineObj = (x: mixed): {[string]: mixed} => {
if (x instanceof Object) {
return x
}
throw new Error("Not an object")
}
// More type-specifc refinement functions
const refineResources = (x: mixed): $ElementType<MyLocals, 'resources'> => {
const anObj = refineObj(x)
return Object.keys(anObj)
.reduce((acc, k) => Object.assign(acc, { [k]: refineString(anObj[k]) }), {})
}
const refineMyLocals = (x: mixed): MyLocals => {
const {version, resources} = refineObj(x)
return {
version: refineNumber(version),
resources: refineResources(resources)
}
}
// Now use them to assert a type
const myLocals: MyLocals = refineMyLocals(locals)
const version: number = myLocals.version;
const resources: {[string]: string} = myLocals.resources;
或者,如果 libdef 在 flow-typed
文件夹中,只需进入那里并更改 libdef。它将使该类型特定于您的项目,但它可能是处理它的最有效方法,假设您不需要代码中其他地方的 [name: string]: mixed
类型。