mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-26 14:50:20 +01:00
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,
|
Emoji: packedEmojiSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Packed = SchemaTypeDef<typeof refs[x]>; とすると展開されてマウスホバー時に型表示が使い物にならなくなる
|
export type Packed<x extends keyof typeof refs> = SchemaType<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]>;
|
|
||||||
|
|
||||||
type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
|
type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
|
||||||
type StringDefToType<T extends TypeStringef> =
|
type StringDefToType<T extends TypeStringef> =
|
||||||
|
@ -107,31 +100,20 @@ export interface Schema extends OfSchema {
|
||||||
readonly minLength?: number;
|
readonly minLength?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type OptionalPropertyNames<T extends Obj> = {
|
type RequiredPropertyNames<s extends Obj> = {
|
||||||
[K in keyof T]: T[K]['optional'] extends true ? K : never
|
[K in keyof s]:
|
||||||
}[keyof T];
|
// K is not optional
|
||||||
|
s[K]['optional'] extends false ? K :
|
||||||
type NonOptionalPropertyNames<T extends Obj> = {
|
// K has default value
|
||||||
[K in keyof T]: T[K]['optional'] extends false ? K : never
|
s[K]['default'] extends null | string | number | boolean | Record<string, unknown> ? K : never
|
||||||
}[keyof T];
|
}[keyof s];
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
export interface Obj { [key: string]: Schema; }
|
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 keyof s]?: SchemaType<s[P]> } &
|
||||||
{ -readonly [P in RequiredProps[number]]: SchemaType<s[P]> } &
|
{ -readonly [P in RequiredProps]: SchemaType<s[P]> } &
|
||||||
{ -readonly [P in OptionalPropertyNames<s>]?: SchemaType<s[P]> } &
|
{ -readonly [P in RequiredPropertyNames<s>]: SchemaType<s[P]> };
|
||||||
{ -readonly [P in NonOptionalPropertyNames<s>]: SchemaType<s[P]> } &
|
|
||||||
{ -readonly [P in DefaultPropertyNames<s>]: SchemaType<s[P]> };
|
|
||||||
|
|
||||||
type NullOrUndefined<p extends Schema, T> =
|
type NullOrUndefined<p extends Schema, T> =
|
||||||
p['nullable'] extends true
|
p['nullable'] extends true
|
||||||
|
@ -142,11 +124,12 @@ type NullOrUndefined<p extends Schema, T> =
|
||||||
? (T | undefined)
|
? (T | undefined)
|
||||||
: T;
|
: 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;
|
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
|
// 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 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;
|
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 'boolean' ? boolean :
|
||||||
p['type'] extends 'object' ? (
|
p['type'] extends 'object' ? (
|
||||||
p['ref'] extends keyof typeof refs ? Packed<p['ref']> :
|
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['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & Partial<UnionToIntersection<UnionSchemaType<p['anyOf']>>> :
|
||||||
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
||||||
any
|
any
|
||||||
|
|
|
@ -32,7 +32,7 @@ export class AppRepository extends Repository<App> {
|
||||||
...(me ? {
|
...(me ? {
|
||||||
isAuthorized: await AccessTokens.count({
|
isAuthorized: await AccessTokens.count({
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
userId: me,
|
userId: me.id,
|
||||||
}).then(count => count > 0),
|
}).then(count => count > 0),
|
||||||
} : {}),
|
} : {}),
|
||||||
};
|
};
|
||||||
|
|
|
@ -65,5 +65,5 @@ export default define(meta, paramDef, async (ps) => {
|
||||||
imageUrl: ps.imageUrl,
|
imageUrl: ps.imageUrl,
|
||||||
}).then(x => Announcements.findOneOrFail(x.identifiers[0]));
|
}).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',
|
kind: 'read:gallery-likes',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
properties: {
|
items: {
|
||||||
id: {
|
type: 'object',
|
||||||
type: 'string',
|
optional: false, nullable: false,
|
||||||
optional: false, nullable: false,
|
properties: {
|
||||||
format: 'id',
|
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;
|
} as const;
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,23 @@ export const meta = {
|
||||||
kind: 'read:page-likes',
|
kind: 'read:page-likes',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
properties: {
|
items: {
|
||||||
id: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
optional: false, nullable: false,
|
id: {
|
||||||
format: '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;
|
} as const;
|
||||||
|
|
||||||
|
@ -47,5 +50,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
.take(ps.limit)
|
.take(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
return await PageLikes.packMany(likes, user);
|
return PageLikes.packMany(likes, user);
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,46 +12,7 @@ export const meta = {
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
properties: {
|
ref: 'App',
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -14,12 +14,12 @@ export const meta = {
|
||||||
properties: {
|
properties: {
|
||||||
state: {
|
state: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: true, nullable: false,
|
||||||
enum: ['already-subscribed', 'subscribed'],
|
enum: ['already-subscribed', 'subscribed'],
|
||||||
},
|
},
|
||||||
key: {
|
key: {
|
||||||
type: 'string',
|
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) {
|
if (exist != null) {
|
||||||
return {
|
return {
|
||||||
state: 'already-subscribed',
|
state: 'already-subscribed' as const,
|
||||||
key: instance.swPublicKey,
|
key: instance.swPublicKey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state: 'subscribed',
|
state: 'subscribed' as const,
|
||||||
key: instance.swPublicKey,
|
key: instance.swPublicKey,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,6 +84,7 @@ export interface MainStreamTypes {
|
||||||
};
|
};
|
||||||
driveFileCreated: Packed<'DriveFile'>;
|
driveFileCreated: Packed<'DriveFile'>;
|
||||||
readAntenna: Antenna;
|
readAntenna: Antenna;
|
||||||
|
receiveFollowRequest: Packed<'User'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DriveStreamTypes {
|
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 { genRsaKeyPair } from '@/misc/gen-key-pair';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { UserProfile } from '@/models/entities/user-profile';
|
import { UserProfile } from '@/models/entities/user-profile';
|
||||||
import { getConnection } from 'typeorm';
|
import { getConnection, ObjectLiteral } from 'typeorm';
|
||||||
import { genId } from '@/misc/gen-id';
|
import { genId } from '@/misc/gen-id';
|
||||||
import { UserKeypair } from '@/models/entities/user-keypair';
|
import { UserKeypair } from '@/models/entities/user-keypair';
|
||||||
import { UsedUsername } from '@/models/entities/used-username';
|
import { UsedUsername } from '@/models/entities/used-username';
|
||||||
|
@ -21,7 +21,7 @@ export async function createSystemUser(username: string) {
|
||||||
|
|
||||||
const keyPair = await genRsaKeyPair(4096);
|
const keyPair = await genRsaKeyPair(4096);
|
||||||
|
|
||||||
let account!: User;
|
let account!: User | ObjectLiteral;
|
||||||
|
|
||||||
// Start transaction
|
// Start transaction
|
||||||
await getConnection().transaction(async transactionalEntityManager => {
|
await getConnection().transaction(async transactionalEntityManager => {
|
||||||
|
|
Loading…
Reference in a new issue