15道优秀的TypeScript练习题(中) typescript基础
connygpt 2024-09-25 15:46 9 浏览
作者:是Peter酱呀
转发链接:https://mp.weixin.qq.com/s/ZR3vbAie-DxGaePngGkI3w
写在开头
- 本次TypeScript一共有15道题,由易道难,可以说是涵盖了所有的使用场景,入门容易,精通难
- 之前的上集有8道题,没有看过的小伙伴,可以看这之前的文章:
- 强烈推荐: 15道优秀的TypeScript练习题(上)
正式开始
- 第八题,模拟动态返回数据,我使用的是泛型解题,此时不是最优解法,AdminsApiResponse和DatesApiResponse可以进一步封装抽象成一个接口.有兴趣的可以继续优化
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
}
type responseData = Date;
type Person = User | Admin;
const admins: Admin[] = [
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' },
];
const users: User[] = [
{
type: 'user',
name: 'Max Mustermann',
age: 25,
occupation: 'Chimney sweep',
},
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
];
type AdminsApiResponse<T> =
| {
status: 'success';
data: T[];
}
| {
status: 'error';
error: string;
};
type DatesApiResponse<T> =
| {
status: 'success';
data: T;
}
| {
status: 'error';
error: string;
};
function requestAdmins(callback: (response: AdminsApiResponse<Admin>) => void) {
callback({
status: 'success',
data: admins,
});
}
function requestUsers(callback: (response: AdminsApiResponse<User>) => void) {
callback({
status: 'success',
data: users,
});
}
function requestCurrentServerTime(
callback: (response: DatesApiResponse<number>) => void
) {
callback({
status: 'success',
data: Date.now(),
});
}
function requestCoffeeMachineQueueLength(
callback: (response: AdminsApiResponse<User>) => void
) {
callback({
status: 'error',
error: 'Numeric value has exceeded Number.MAX_SAFE_INTEGER.',
});
}
function logPerson(person: Person) {
console.log(
` - ${chalk.green(person.name)}, ${person.age}, ${
person.type === 'admin' ? person.role : person.occupation
}`
);
}
function startTheApp(callback: (error: Error | null) => void) {
requestAdmins((adminsResponse) => {
console.log(chalk.yellow('Admins:'));
if (adminsResponse.status === 'success') {
adminsResponse.data.forEach(logPerson);
} else {
return callback(new Error(adminsResponse.error));
}
console.log();
requestUsers((usersResponse) => {
console.log(chalk.yellow('Users:'));
if (usersResponse.status === 'success') {
usersResponse.data.forEach(logPerson);
} else {
return callback(new Error(usersResponse.error));
}
console.log();
requestCurrentServerTime((serverTimeResponse) => {
console.log(chalk.yellow('Server time:'));
if (serverTimeResponse.status === 'success') {
console.log(
` ${new Date(serverTimeResponse.data).toLocaleString()}`
);
} else {
return callback(new Error(serverTimeResponse.error));
}
console.log();
requestCoffeeMachineQueueLength((coffeeMachineQueueLengthResponse) => {
console.log(chalk.yellow('Coffee machine queue length:'));
if (coffeeMachineQueueLengthResponse.status === 'success') {
console.log(` ${coffeeMachineQueueLengthResponse.data}`);
} else {
return callback(new Error(coffeeMachineQueueLengthResponse.error));
}
callback(null);
});
});
});
});
}
startTheApp((e: Error | null) => {
console.log();
if (e) {
console.log(
`Error: "${e.message}", but it's fine, sometimes errors are inevitable.`
);
} else {
console.log('Success!');
}
});
- 第九题,还是考察泛型,promisify的编写,传入一个返回promise的函数,函数接受一个参数,这个参数是一个函数,它有对应的根据泛型生成的参数,返回值为void,同样这个函数的参数也为函数,返回值也为void
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
}
type Person = User | Admin;
const admins: Admin[] = [
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }
];
const users: User[] = [
{ type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }
];
type ApiResponse<T> = (
{
status: 'success';
data: T;
} |
{
status: 'error';
error: string;
}
);
function promisify<T>(fn: (callback: (arg: ApiResponse<T>) => void) => void): () => Promise<T>
function promisify(arg: unknown): unknown {
return null;
}
const oldApi = {
requestAdmins(callback: (response: ApiResponse<Admin[]>) => void) {
callback({
status: 'success',
data: admins
});
},
requestUsers(callback: (response: ApiResponse<User[]>) => void) {
callback({
status: 'success',
data: users
});
},
requestCurrentServerTime(callback: (response: ApiResponse<number>) => void) {
callback({
status: 'success',
data: Date.now()
});
},
requestCoffeeMachineQueueLength(callback: (response: ApiResponse<number>) => void) {
callback({
status: 'error',
error: 'Numeric value has exceeded Number.MAX_SAFE_INTEGER.'
});
}
};
const api = {
requestAdmins: promisify(oldApi.requestAdmins),
requestUsers: promisify(oldApi.requestUsers),
requestCurrentServerTime: promisify(oldApi.requestCurrentServerTime),
requestCoffeeMachineQueueLength: promisify(oldApi.requestCoffeeMachineQueueLength)
};
function logPerson(person: Person) {
console.log(
` - ${chalk.green(person.name)}, ${person.age}, ${person.type === 'admin' ? person.role : person.occupation}`
);
}
async function startTheApp() {
console.log(chalk.yellow('Admins:'));
(await api.requestAdmins()).forEach(logPerson);
console.log();
console.log(chalk.yellow('Users:'));
(await api.requestUsers()).forEach(logPerson);
console.log();
console.log(chalk.yellow('Server time:'));
console.log(` ${new Date(await api.requestCurrentServerTime()).toLocaleString()}`);
console.log();
console.log(chalk.yellow('Coffee machine queue length:'));
console.log(` ${await api.requestCoffeeMachineQueueLength()}`);
}
startTheApp().then(
() => {
console.log('Success!');
},
(e: Error) => {
console.log(`Error: "${e.message}", but it's fine, sometimes errors are inevitable.`);
}
);
- 第十题,考察declaer module
declare module 'str-utils' {
export function strReverse(arg:string): string;
export function strToLower(arg:string): string;
export function strToUpper(arg:string): string;
export function strRandomize(arg:string): string;
export function strInvertCase(arg:string): string;
}
import {
strReverse,
strToLower,
strToUpper,
strRandomize,
strInvertCase
} from 'str-utils';
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
}
type Person = User | Admin;
const admins: Admin[] = [
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' },
{ type: 'admin', name: 'Steve', age: 40, role: 'Steve' },
{ type: 'admin', name: 'Will Bruces', age: 30, role: 'Overseer' },
{ type: 'admin', name: 'Superwoman', age: 28, role: 'Customer support' }
];
const users: User[] = [
{ type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
{ type: 'user', name: 'Moses', age: 70, occupation: 'Desert guide' },
{ type: 'user', name: 'Superman', age: 28, occupation: 'Ordinary person' },
{ type: 'user', name: 'Inspector Gadget', age: 31, occupation: 'Undercover' }
];
const isAdmin = (person: Person): person is Admin => person.type === 'admin';
const isUser = (person: Person): person is User => person.type === 'user';
const nameDecorators = [
strReverse,
strToLower,
strToUpper,
strRandomize,
strInvertCase
];
function logPerson(person: Person) {
let additionalInformation: string = '';
if (isAdmin(person)) {
additionalInformation = person.role;
}
if (isUser(person)) {
additionalInformation = person.occupation;
}
const randomNameDecorator = nameDecorators[
Math.round(Math.random() * (nameDecorators.length - 1))
];
const name = randomNameDecorator(person.name);
console.log(
` - ${chalk.green(name)}, ${person.age}, ${additionalInformation}`
);
}
([] as Person[])
.concat(users, admins)
.forEach(logPerson);
- 第十一题,我使用了泛型和declare module解题,如果你有更优解法,可以跟我聊聊,自认为这题没毛病.上面那道题我说两个interface可以进一步优化,也可以参考这个思路
type func = <T>(input: T[], comparator: (a: T, b: T) => number) => T | null;
type index<L> = <T>(input: T[], comparator: (a: T, b: T) => number) => L;
declare module 'stats' {
export const getMaxIndex: index<number>;
export const getMaxElement: func;
export const getMinIndex: index<number>;
export const getMinElement: func;
export const getMedianIndex: index<number>;
export const getMedianElement: func;
export const getAverageValue: func;
}
import {
getMaxIndex,
getMaxElement,
getMinIndex,
getMinElement,
getMedianIndex,
getMedianElement,
getAverageValue
} from 'stats';
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
}
const admins: Admin[] = [
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' },
{ type: 'admin', name: 'Steve', age: 40, role: 'Steve' },
{ type: 'admin', name: 'Will Bruces', age: 30, role: 'Overseer' },
{ type: 'admin', name: 'Superwoman', age: 28, role: 'Customer support' }
];
const users: User[] = [
{ type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
{ type: 'user', name: 'Moses', age: 70, occupation: 'Desert guide' },
{ type: 'user', name: 'Superman', age: 28, occupation: 'Ordinary person' },
{ type: 'user', name: 'Inspector Gadget', age: 31, occupation: 'Undercover' }
];
function logUser(user: User | null) {
if (!user) {
console.log(' - none');
return;
}
const pos = users.indexOf(user) + 1;
console.log(` - #${pos} User: ${chalk.green(user.name)}, ${user.age}, ${user.occupation}`);
}
function logAdmin(admin: Admin | null) {
if (!admin) {
console.log(' - none');
return;
}
const pos = admins.indexOf(admin) + 1;
console.log(` - #${pos} Admin: ${chalk.green(admin.name)}, ${admin.age}, ${admin.role}`);
}
const compareUsers = (a: User, b: User) => a.age - b.age;
const compareAdmins = (a: Admin, b: Admin) => a.age - b.age;
const colorizeIndex = (value: number) => chalk.red(String(value + 1));
console.log(chalk.yellow('Youngest user:'));
logUser(getMinElement(users, compareUsers));
console.log(` - was ${colorizeIndex(getMinIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Median user:'));
logUser(getMedianElement(users, compareUsers));
console.log(` - was ${colorizeIndex(getMedianIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Oldest user:'));
logUser(getMaxElement(users, compareUsers));
console.log(` - was ${colorizeIndex(getMaxIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Average user age:'));
console.log(` - ${chalk.red(String(getAverageValue(users, ({age}: User) => age)))} years`);
console.log();
console.log(chalk.yellow('Youngest admin:'));
logAdmin(getMinElement(admins, compareAdmins));
console.log(` - was ${colorizeIndex(getMinIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Median admin:'));
logAdmin(getMedianElement(admins, compareAdmins));
console.log(` - was ${colorizeIndex(getMedianIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Oldest admin:'));
logAdmin(getMaxElement(admins, compareAdmins));
console.log(` - was ${colorizeIndex(getMaxIndex(users, compareUsers))}th to register`);
console.log();
console.log(chalk.yellow('Average admin age:'));
console.log(` - ${chalk.red(String(getAverageValue(admins, ({age}: Admin) => age)))} years`);
- 第十二题,考察模块扩充模式和泛型
import 'date-wizard';
declare module 'date-wizard' {
// Add your module extensions here.
export function pad<T>(name: T): T;
export function dateDetails<T>(name: T): { hours: number };
}
//..
import * as dateWizard from 'date-wizard';
import './module-augmentations/date-wizard';
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
registered: Date;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
registered: Date;
}
type Person = User | Admin;
const admins: Admin[] = [
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator', registered: new Date('2016-06-01T16:23:13') },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver', registered: new Date('2017-02-11T12:12:11') },
{ type: 'admin', name: 'Steve', age: 40, role: 'Steve', registered: new Date('2018-01-05T11:02:30') },
{ type: 'admin', name: 'Will Bruces', age: 30, role: 'Overseer', registered: new Date('2018-08-12T10:01:24') },
{ type: 'admin', name: 'Superwoman', age: 28, role: 'Customer support', registered: new Date('2019-03-25T07:51:05') }
];
const users: User[] = [
{ type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep', registered: new Date('2016-02-15T09:25:13') },
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut', registered: new Date('2016-03-23T12:47:03') },
{ type: 'user', name: 'Moses', age: 70, occupation: 'Desert guide', registered: new Date('2017-02-19T17:22:56') },
{ type: 'user', name: 'Superman', age: 28, occupation: 'Ordinary person', registered: new Date('2018-02-25T19:44:28') },
{ type: 'user', name: 'Inspector Gadget', age: 31, occupation: 'Undercover', registered: new Date('2019-03-25T09:29:12') }
];
const isAdmin = (person: Person): person is Admin => person.type === 'admin';
const isUser = (person: Person): person is User => person.type === 'user';
function logPerson(person: Person, index: number) {
let additionalInformation: string = '';
if (isAdmin(person)) {
additionalInformation = person.role;
}
if (isUser(person)) {
additionalInformation = person.occupation;
}
let registeredAt = dateWizard(person.registered, '{date}.{month}.{year} {hours}:{minutes}');
let num = `#${dateWizard.pad(index + 1)}`;
console.log(
` - ${num}: ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}, ${registeredAt}`
);
}
console.log(chalk.yellow('All users:'));
([] as Person[])
.concat(users, admins)
.forEach(logPerson);
console.log();
console.log(chalk.yellow('Early birds:'));
([] as Person[])
.concat(users, admins)
.filter((person) => dateWizard.dateDetails(person.registered).hours < 10)
.forEach(logPerson);
- 第十三题,略有难度,考察联合类型、类型断言、泛型,由于数据库的查询,find方法可能传入的参数是多种多样的,为了满足以下的find使用场景,需要定义Database这个类
interface User {
_id: number;
name: string;
age: number;
occupation: string;
registered: string;
}
interface Admin {
_id: number;
name: string;
age: number;
role: string;
registered: string;
}
async function testUsersDatabase() {
const usersDatabase = new Database<User>(path.join(__dirname, 'users.txt'), [
'name',
'occupation',
]);
// $eq operator means "===", syntax {fieldName: {$gt: value}}
// see more https://docs.mongodb.com/manual/reference/operator/query/eq/
expect(
(await usersDatabase.find({ occupation: { $eq: 'Magical entity' } })).map(
({ _id }) => _id
)
).to.have.same.members([6, 8]);
expect(
(
await usersDatabase.find({
age: { $eq: 31 },
name: { $eq: 'Inspector Gadget' },
})
)[0]._id
).to.equal(5);
// $gt operator means ">", syntax {fieldName: {$gt: value}}
// see more https://docs.mongodb.com/manual/reference/operator/query/gt/
expect(
(await usersDatabase.find({ age: { $gt: 30 } })).map(({ _id }) => _id)
).to.have.same.members([3, 5, 6, 8]);
// $lt operator means "<", syntax {fieldName: {$lt: value}}
// see more https://docs.mongodb.com/manual/reference/operator/query/lt/
expect(
(await usersDatabase.find({ age: { $lt: 30 } })).map(({ _id }) => _id)
).to.have.same.members([0, 2, 4, 7]);
// $and condition is satisfied when all the nested conditions are satisfied: {$and: [condition1, condition2, ...]}
// see more https://docs.mongodb.com/manual/reference/operator/query/and/
// These examples return the same result:
// usersDatabase.find({age: {$eq: 31}, name: {$eq: 'Inspector Gadget'}});
// usersDatabase.find({$and: [{age: {$eq: 31}}, {name: {$eq: 'Inspector Gadget'}}]});
expect(
(
await usersDatabase.find({
$and: [{ age: { $gt: 30 } }, { age: { $lt: 40 } }],
})
).map(({ _id }) => _id)
).to.have.same.members([5, 6]);
// $or condition is satisfied when at least one nested condition is satisfied: {$or: [condition1, condition2, ...]}
// see more https://docs.mongodb.com/manual/reference/operator/query/or/
expect(
(
await usersDatabase.find({
$or: [{ age: { $gt: 90 } }, { age: { $lt: 30 } }],
})
).map(({ _id }) => _id)
).to.have.same.members([0, 2, 4, 7, 8]);
// $text operator means full text search. For simplicity this means finding words from the full-text search
// fields which are specified in the Database constructor. No stemming or language processing other than
// being case insensitive is not required.
// Syntax {$text: 'Hello World'} - this return all records having both words in its full-text search fields.
// It is also possible that queried words are spread among different full-text search fields.
expect(
(await usersDatabase.find({ $text: 'max' })).map(({ _id }) => _id)
).to.have.same.members([0, 7]);
expect(
(await usersDatabase.find({ $text: 'Hey' })).map(({ _id }) => _id)
).to.have.same.members([]);
// $in operator checks if entry field value is within the specified list of accepted values.
// Syntax {fieldName: {$in: [value1, value2, value3]}}
// Equivalent to {$or: [{fieldName: {$eq: value1}}, {fieldName: {$eq: value2}}, {fieldName: {$eq: value3}}]}
// see more https://docs.mongodb.com/manual/reference/operator/query/in/
expect(
(await usersDatabase.find({ _id: { $in: [0, 1, 2] } })).map(
({ _id }) => _id
)
).to.have.same.members([0, 2]);
expect(
(await usersDatabase.find({ age: { $in: [31, 99] } })).map(({ _id }) => _id)
).to.have.same.members([5, 8]);
}
async function testAdminsDatabase() {
const adminsDatabase = new Database<Admin>(
path.join(__dirname, 'admins.txt'),
['name', 'role']
);
expect(
(await adminsDatabase.find({ role: { $eq: 'Administrator' } })).map(
({ _id }) => _id
)
).to.have.same.members([0, 6]);
expect(
(
await adminsDatabase.find({
age: { $eq: 51 },
name: { $eq: 'Bill Gates' },
})
)[0]._id
).to.equal(7);
expect(
(await adminsDatabase.find({ age: { $gt: 30 } })).map(({ _id }) => _id)
).to.have.same.members([0, 2, 3, 6, 7, 8]);
expect(
(await adminsDatabase.find({ age: { $lt: 30 } })).map(({ _id }) => _id)
).to.have.same.members([5]);
expect(
(
await adminsDatabase.find({
$and: [{ age: { $gt: 30 } }, { age: { $lt: 40 } }],
})
).map(({ _id }) => _id)
).to.have.same.members([0, 8]);
expect(
(
await adminsDatabase.find({
$or: [{ age: { $lt: 30 } }, { age: { $gt: 60 } }],
})
).map(({ _id }) => _id)
).to.have.same.members([2, 5]);
expect(
(await adminsDatabase.find({ $text: 'WILL' })).map(({ _id }) => _id)
).to.have.same.members([4, 6]);
expect(
(await adminsDatabase.find({ $text: 'Administrator' })).map(
({ _id }) => _id
)
).to.have.same.members([0, 6]);
expect(
(await adminsDatabase.find({ $text: 'Br' })).map(({ _id }) => _id)
).to.have.same.members([]);
expect(
(await adminsDatabase.find({ _id: { $in: [0, 1, 2, 3] } })).map(
({ _id }) => _id
)
).to.have.same.members([0, 2, 3]);
expect(
(await adminsDatabase.find({ age: { $in: [30, 28] } })).map(
({ _id }) => _id
)
).to.have.same.members([4, 5]);
}
Promise.all([testUsersDatabase(), testAdminsDatabase()]).then(
() => console.log('All tests have succeeded, congratulations!'),
(e) => console.error(e.stack)
);
//Database
import * as fs from 'fs';
export type FieldOp =
| { $eq: string | number }
| { $gt: string | number }
| { $lt: string | number }
| { $in: (string | number)[] };
export type Query =
| { $and: Query[] }
| { $or: Query[] }
| { $text: string }
| ({ [field: string]: FieldOp } & {
$and?: never;
$or?: never;
$text?: never;
});
function matchOp(op: FieldOp, v: any) {
if ('$eq' in op) {
return v === op['$eq'];
} else if ('$gt' in op) {
return v > op['$gt'];
} else if ('$lt' in op) {
return v < op['$lt'];
} else if ('$in' in op) {
return op['$in'].includes(v);
}
throw new Error(`Unrecognized op: ${op}`);
}
function matches(q: Query, r: unknown): boolean {
if ('$and' in q) {
return q.$and!.every((subq) => matches(subq, r));
} else if ('$or' in q) {
return q.$or!.some((subq) => matches(subq, r));
} else if ('$text' in q) {
const words = q.$text!.toLowerCase().split(' ');
return words.every((w) => (r as any).$index[w]);
}
return Object.entries(q).every(([k, v]) => matchOp(v, (r as any)[k]));
}
export class Database<T> {
protected filename: string;
protected fullTextSearchFieldNames: string[];
protected records: T[];
constructor(filename: string, fullTextSearchFieldNames: string[]) {
this.filename = filename;
this.filename = filename;
this.fullTextSearchFieldNames = fullTextSearchFieldNames;
this.fullTextSearchFieldNames = fullTextSearchFieldNames;
const text = fs.readFileSync(filename, 'utf8');
const lines = text.split('\n');
this.records = lines
.filter((line) => line.startsWith('E'))
.map((line) => JSON.parse(line.slice(1)))
.map((obj) => {
obj.$index = {};
for (const f of fullTextSearchFieldNames) {
const text = obj[f];
for (const word of text.split(' ')) {
obj.$index[word.toLowerCase()] = true;
}
}
return obj;
});
}
async find(query: Query): Promise<T[]> {
return this.records.filter((r) => matches(query, r));
}
}
写在最后
- 我是Peter酱,前端架构师 擅长跨平台和极限场景性能优化 不定期会给你们推送高质量原创文章,公众号回复:加群即可加入群聊
- 我把我的往期文章、源码都放在一个仓库了,手写vue React webpack weboscket redis 静态资源服务器(实现http缓存) redux promise react-redux 微前端框架 ssr等,进阶前端专家不可或缺.
作者:是Peter酱呀
转发链接:https://mp.weixin.qq.com/s/ZR3vbAie-DxGaePngGkI3w
相关推荐
- 3分钟让你的项目支持AI问答模块,完全开源!
-
hello,大家好,我是徐小夕。之前和大家分享了很多可视化,零代码和前端工程化的最佳实践,今天继续分享一下最近开源的Next-Admin的最新更新。最近对这个项目做了一些优化,并集成了大家比较关注...
- 干货|程序员的副业挂,12个平台分享
-
1、D2adminD2Admin是一个完全开源免费的企业中后台产品前端集成方案,使用最新的前端技术栈,小于60kb的本地首屏js加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助...
- Github标星超200K,这10个可视化面板你知道几个
-
在Github上有很多开源免费的后台控制面板可以选择,但是哪些才是最好、最受欢迎的可视化控制面板呢?今天就和大家推荐Github上10个好看又流行的可视化面板:1.AdminLTEAdminLTE是...
- 开箱即用的炫酷中后台前端开源框架第二篇
-
#头条创作挑战赛#1、SoybeanAdmin(1)介绍:SoybeanAdmin是一个基于Vue3、Vite3、TypeScript、NaiveUI、Pinia和UnoCSS的清新优...
- 搭建React+AntDeign的开发环境和框架
-
搭建React+AntDeign的开发环境和框架随着前端技术的不断发展,React和AntDesign已经成为越来越多Web应用程序的首选开发框架。React是一个用于构建用户界面的JavaScrip...
- 基于.NET 5实现的开源通用权限管理平台
-
??大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!??今天小编推荐一款基于.NE...
- StreamPark - 大数据流计算引擎
-
使用Docker完成StreamPark的部署??1.基于h2和docker-compose进行StreamPark部署wgethttps://raw.githubusercontent.com/a...
- 教你使用UmiJS框架开发React
-
1、什么是Umi.js?umi,中文可发音为乌米,是一个可插拔的企业级react应用框架。你可以将它简单地理解为一个专注性能的类next.js前端框架,并通过约定、自动生成和解析代码等方式来辅助...
- 简单在线流程图工具在用例设计中的运用
-
敏捷模式下,测试团队的用例逐渐简化以适应快速的发版节奏,大家很早就开始运用思维导图工具比如xmind来编写测试方法、测试点。如今不少已经不少利用开源的思维导图组件(如百度脑图...)来构建测试测试...
- 【开源分享】神奇的大数据实时平台框架,让Flink&Spark开发更简单
-
这是一个神奇的框架,让Flink|Spark开发更简单,一站式大数据实时平台!他就是StreamX!什么是StreamX大数据技术如今发展的如火如荼,已经呈现百花齐放欣欣向荣的景象,实时处理流域...
- 聊聊规则引擎的调研及实现全过程
-
摘要本期主要以规则引擎业务实现为例,陈述在陌生业务前如何进行业务深入、调研、技术选型、设计及实现全过程分析,如果你对规则引擎不感冒、也可以从中了解一些抽象实现过程。诉求从硬件采集到的数据提供的形式多种...
- 【开源推荐】Diboot 2.0.5 发布,自动化开发助理
-
一、前言Diboot2.0.5版本已于近日发布,在此次发布中,我们新增了file-starter组件,完善了iam-starter组件,对core核心进行了相关优化,让devtools也支持对IAM...
- 微软推出Copilot Actions,使用人工智能自动执行重复性任务
-
IT之家11月19日消息,微软在今天举办的Ignite大会上宣布了一系列新功能,旨在进一步提升Microsoft365Copilot的智能化水平。其中最引人注目的是Copilot...
- Electron 使用Selenium和WebDriver
-
本节我们来学习如何在Electron下使用Selenium和WebDriver。SeleniumSelenium是ThoughtWorks提供的一个强大的基于浏览器的开源自动化测试工具...
- Quick 'n Easy Web Builder 11.1.0设计和构建功能齐全的网页的工具
-
一个实用而有效的应用程序,能够让您轻松构建、创建和设计个人的HTML网站。Quick'nEasyWebBuilder是一款全面且轻巧的软件,为用户提供了一种简单的方式来创建、编辑...
- 一周热门
- 最近发表
- 标签列表
-
- kubectlsetimage (56)
- mysqlinsertoverwrite (53)
- addcolumn (54)
- helmpackage (54)
- varchar最长多少 (61)
- 类型断言 (53)
- protoc安装 (56)
- jdk20安装教程 (60)
- rpm2cpio (52)
- 控制台打印 (63)
- 401unauthorized (51)
- vuexstore (68)
- druiddatasource (60)
- 企业微信开发文档 (51)
- rendertexture (51)
- speedphp (52)
- gitcommit-am (68)
- bashecho (64)
- str_to_date函数 (58)
- yum下载包及依赖到本地 (72)
- jstree中文api文档 (59)
- mvnw文件 (58)
- rancher安装 (63)
- nginx开机自启 (53)
- .netcore教程 (53)