SchemaTypeの型計算量を削減 (#8332)
* schema typeの型計算量を削減 * reduce some type error * wip * fix * clean up * more shrink
This commit is contained in:
		
							parent
							
								
									b6db709e02
								
							
						
					
					
						commit
						fd8f8162e1
					
				
					 9 changed files with 57 additions and 105 deletions
				
			
		|  | @ -63,14 +63,7 @@ export const refs = { | |||
| 	Emoji: packedEmojiSchema, | ||||
| }; | ||||
| 
 | ||||
| // Packed = SchemaTypeDef<typeof refs[x]>; とすると展開されてマウスホバー時に型表示が使い物にならなくなる
 | ||||
| // ObjType<r['properties']>を指定すると(なぜか)展開されずにPacked<'Hoge'>と表示される
 | ||||
| type PackedDef<r extends { properties?: Obj; oneOf?: ReadonlyArray<Schema>; allOf?: ReadonlyArray<Schema> }> = | ||||
| 	r['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<r['allOf']>> : | ||||
| 	r['oneOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<r['oneOf']> : | ||||
| 	r['properties'] extends Obj ? ObjType<r['properties'], any> : | ||||
| 	never; | ||||
| export type Packed<x extends keyof typeof refs> = PackedDef<typeof refs[x]>; | ||||
| export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>; | ||||
| 
 | ||||
| type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any'; | ||||
| type StringDefToType<T extends TypeStringef> = | ||||
|  | @ -107,31 +100,20 @@ export interface Schema extends OfSchema { | |||
| 	readonly minLength?: number; | ||||
| } | ||||
| 
 | ||||
| type OptionalPropertyNames<T extends Obj> = { | ||||
| 	[K in keyof T]: T[K]['optional'] extends true ? K : never | ||||
| }[keyof T]; | ||||
| 
 | ||||
| type NonOptionalPropertyNames<T extends Obj> = { | ||||
| 	[K in keyof T]: T[K]['optional'] extends false ? K : never | ||||
| }[keyof T]; | ||||
| 
 | ||||
| type DefaultPropertyNames<T extends Obj> = { | ||||
| 	[K in keyof T]: T[K]['default'] extends null ? K : | ||||
| 		T[K]['default'] extends string ? K : | ||||
| 		T[K]['default'] extends number ? K : | ||||
| 		T[K]['default'] extends boolean ? K : | ||||
| 		T[K]['default'] extends Record<string, unknown> ? K : | ||||
| 		never | ||||
| }[keyof T]; | ||||
| type RequiredPropertyNames<s extends Obj> = { | ||||
| 	[K in keyof s]: | ||||
| 		// K is not optional
 | ||||
| 		s[K]['optional'] extends false ? K : | ||||
| 		// K has default value
 | ||||
| 		s[K]['default'] extends null | string | number | boolean | Record<string, unknown> ? K : never | ||||
| }[keyof s]; | ||||
| 
 | ||||
| export interface Obj { [key: string]: Schema; } | ||||
| 
 | ||||
| export type ObjType<s extends Obj, RequiredProps extends ReadonlyArray<keyof s>> = | ||||
| export type ObjType<s extends Obj, RequiredProps extends keyof s> = | ||||
| 	{ -readonly [P in keyof s]?: SchemaType<s[P]> } & | ||||
| 	{ -readonly [P in RequiredProps[number]]: SchemaType<s[P]> } & | ||||
| 	{ -readonly [P in OptionalPropertyNames<s>]?: SchemaType<s[P]> } & | ||||
| 	{ -readonly [P in NonOptionalPropertyNames<s>]: SchemaType<s[P]> } & | ||||
| 	{ -readonly [P in DefaultPropertyNames<s>]: SchemaType<s[P]> }; | ||||
| 	{ -readonly [P in RequiredProps]: SchemaType<s[P]> } & | ||||
| 	{ -readonly [P in RequiredPropertyNames<s>]: SchemaType<s[P]> }; | ||||
| 
 | ||||
| type NullOrUndefined<p extends Schema, T> = | ||||
| 	p['nullable'] extends true | ||||
|  | @ -142,11 +124,12 @@ type NullOrUndefined<p extends Schema, T> = | |||
| 			? (T | undefined) | ||||
| 			: T; | ||||
| 
 | ||||
| // 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
 | ||||
| // https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
 | ||||
| // Get intersection from union 
 | ||||
| type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; | ||||
| 
 | ||||
| // https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552
 | ||||
| // 単純にSchemaTypeDef<X>で判定するだけではダメ
 | ||||
| // To get union, we use `Foo extends any ? Hoge<Foo> : never`
 | ||||
| type UnionSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? SchemaType<X> : never; | ||||
| type ArrayUnion<T> = T extends any ? Array<T> : never;  | ||||
| 
 | ||||
|  | @ -163,7 +146,7 @@ export type SchemaTypeDef<p extends Schema> = | |||
| 	p['type'] extends 'boolean' ? boolean : | ||||
| 	p['type'] extends 'object' ? ( | ||||
| 		p['ref'] extends keyof typeof refs ? Packed<p['ref']> : | ||||
| 		p['properties'] extends NonNullable<Obj> ? ObjType<p['properties'], NonNullable<p['required']>> : | ||||
| 		p['properties'] extends NonNullable<Obj> ? ObjType<p['properties'], NonNullable<p['required']>[number]> : | ||||
| 		p['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & Partial<UnionToIntersection<UnionSchemaType<p['anyOf']>>> : | ||||
| 		p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> : | ||||
| 		any | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ export class AppRepository extends Repository<App> { | |||
| 			...(me ? { | ||||
| 				isAuthorized: await AccessTokens.count({ | ||||
| 					appId: app.id, | ||||
| 					userId: me, | ||||
| 					userId: me.id, | ||||
| 				}).then(count => count > 0), | ||||
| 			} : {}), | ||||
| 		}; | ||||
|  |  | |||
|  | @ -65,5 +65,5 @@ export default define(meta, paramDef, async (ps) => { | |||
| 		imageUrl: ps.imageUrl, | ||||
| 	}).then(x => Announcements.findOneOrFail(x.identifiers[0])); | ||||
| 
 | ||||
| 	return announcement; | ||||
| 	return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); | ||||
| }); | ||||
|  |  | |||
|  | @ -10,20 +10,24 @@ export const meta = { | |||
| 	kind: 'read:gallery-likes', | ||||
| 
 | ||||
| 	res: { | ||||
| 		type: 'object', | ||||
| 		type: 'array', | ||||
| 		optional: false, nullable: false, | ||||
| 		properties: { | ||||
| 			id: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: false, | ||||
| 				format: 'id', | ||||
| 		items: { | ||||
| 			type: 'object', | ||||
| 			optional: false, nullable: false, | ||||
| 			properties: { | ||||
| 				id: { | ||||
| 					type: 'string', | ||||
| 					optional: false, nullable: false, | ||||
| 					format: 'id', | ||||
| 				}, | ||||
| 				post: { | ||||
| 					type: 'object', | ||||
| 					optional: false, nullable: false, | ||||
| 					ref: 'GalleryPost', | ||||
| 				}, | ||||
| 			}, | ||||
| 			page: { | ||||
| 				type: 'object', | ||||
| 				optional: false, nullable: false, | ||||
| 				ref: 'GalleryPost', | ||||
| 			}, | ||||
| 		}, | ||||
| 		} | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,20 +10,23 @@ export const meta = { | |||
| 	kind: 'read:page-likes', | ||||
| 
 | ||||
| 	res: { | ||||
| 		type: 'object', | ||||
| 		type: 'array', | ||||
| 		optional: false, nullable: false, | ||||
| 		properties: { | ||||
| 			id: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: false, | ||||
| 				format: 'id', | ||||
| 		items: { | ||||
| 			type: 'object', | ||||
| 			properties: { | ||||
| 				id: { | ||||
| 					type: 'string', | ||||
| 					optional: false, nullable: false, | ||||
| 					format: 'id', | ||||
| 				}, | ||||
| 				page: { | ||||
| 					type: 'object', | ||||
| 					optional: false, nullable: false, | ||||
| 					ref: 'Page', | ||||
| 				}, | ||||
| 			}, | ||||
| 			page: { | ||||
| 				type: 'object', | ||||
| 				optional: false, nullable: false, | ||||
| 				ref: 'Page', | ||||
| 			}, | ||||
| 		}, | ||||
| 		} | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
|  | @ -47,5 +50,5 @@ export default define(meta, paramDef, async (ps, user) => { | |||
| 		.take(ps.limit) | ||||
| 		.getMany(); | ||||
| 
 | ||||
| 	return await PageLikes.packMany(likes, user); | ||||
| 	return PageLikes.packMany(likes, user); | ||||
| }); | ||||
|  |  | |||
|  | @ -12,46 +12,7 @@ export const meta = { | |||
| 		items: { | ||||
| 			type: 'object', | ||||
| 			optional: false, nullable: false, | ||||
| 			properties: { | ||||
| 				id: { | ||||
| 					type: 'string', | ||||
| 					optional: false, nullable: false, | ||||
| 				}, | ||||
| 				name: { | ||||
| 					type: 'string', | ||||
| 					optional: false, nullable: false, | ||||
| 				}, | ||||
| 				callbackUrl: { | ||||
| 					type: 'string', | ||||
| 					optional: false, nullable: false, | ||||
| 				}, | ||||
| 				permission: { | ||||
| 					type: 'array', | ||||
| 					optional: false, nullable: false, | ||||
| 					items: { | ||||
| 						type: 'string', | ||||
| 						optional: false, nullable: false, | ||||
| 					}, | ||||
| 				}, | ||||
| 				secret: { | ||||
| 					type: 'string', | ||||
| 					optional: true, nullable: false, | ||||
| 				}, | ||||
| 				isAuthorized: { | ||||
| 					type: 'object', | ||||
| 					optional: true, nullable: false, | ||||
| 					properties: { | ||||
| 						appId: { | ||||
| 							type: 'string', | ||||
| 							optional: false, nullable: false, | ||||
| 						}, | ||||
| 						userId: { | ||||
| 							type: 'string', | ||||
| 							optional: false, nullable: false, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			ref: 'App', | ||||
| 		}, | ||||
| 	}, | ||||
| } as const; | ||||
|  |  | |||
|  | @ -14,12 +14,12 @@ export const meta = { | |||
| 		properties: { | ||||
| 			state: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: false, | ||||
| 				optional: true, nullable: false, | ||||
| 				enum: ['already-subscribed', 'subscribed'], | ||||
| 			}, | ||||
| 			key: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: false, | ||||
| 				optional: false, nullable: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
|  | @ -49,7 +49,7 @@ export default define(meta, paramDef, async (ps, user) => { | |||
| 
 | ||||
| 	if (exist != null) { | ||||
| 		return { | ||||
| 			state: 'already-subscribed', | ||||
| 			state: 'already-subscribed' as const, | ||||
| 			key: instance.swPublicKey, | ||||
| 		}; | ||||
| 	} | ||||
|  | @ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, user) => { | |||
| 	}); | ||||
| 
 | ||||
| 	return { | ||||
| 		state: 'subscribed', | ||||
| 		state: 'subscribed' as const, | ||||
| 		key: instance.swPublicKey, | ||||
| 	}; | ||||
| }); | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ export interface MainStreamTypes { | |||
| 	}; | ||||
| 	driveFileCreated: Packed<'DriveFile'>; | ||||
| 	readAntenna: Antenna; | ||||
| 	receiveFollowRequest: Packed<'User'>; | ||||
| } | ||||
| 
 | ||||
| export interface DriveStreamTypes { | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import generateNativeUserToken from '../server/api/common/generate-native-user-t | |||
| import { genRsaKeyPair } from '@/misc/gen-key-pair'; | ||||
| import { User } from '@/models/entities/user'; | ||||
| import { UserProfile } from '@/models/entities/user-profile'; | ||||
| import { getConnection } from 'typeorm'; | ||||
| import { getConnection, ObjectLiteral } from 'typeorm'; | ||||
| import { genId } from '@/misc/gen-id'; | ||||
| import { UserKeypair } from '@/models/entities/user-keypair'; | ||||
| import { UsedUsername } from '@/models/entities/used-username'; | ||||
|  | @ -21,7 +21,7 @@ export async function createSystemUser(username: string) { | |||
| 
 | ||||
| 	const keyPair = await genRsaKeyPair(4096); | ||||
| 
 | ||||
| 	let account!: User; | ||||
| 	let account!: User | ObjectLiteral; | ||||
| 
 | ||||
| 	// Start transaction
 | ||||
| 	await getConnection().transaction(async transactionalEntityManager => { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue