我在以下结构中有一个对象:
const geo = {
europe: {
germany: ['berlin', 'hamburg', 'cologne'],
france: ['toulouse', 'paris', 'limoges'],
italy: ['rome', 'venice', 'genoa'],
},
asia: {
india: ['mumbai', 'rajkot', 'pune'],
china: ['shenzhen', 'beijing', 'shanghai'],
nepal: ['kohalpur', 'ghorahi', 'hetauda'],
},
};我想写一个简单的函数,随机选择一个城市,给定的大陆和国家。虽然在我看来一个简单的实现是
const randomElement = (arr) => arr[Math.floor(Math.random() * arr.length)];
const pickCity = (continent, country) => randomElement(geo[continent][country])
// calling `pickCity()`
pickCity("europe", "france") // => we get one city at random, as requested不过,我不知道这种实现是否属于“打得很厉害”函数的范畴,据说这是一种次优实践。
另一方面,如果我试图避免使用这些字符串参数,那么另一种方法将是更加冗长,而且不尊重干法原则:
const pickCityGermany = () => randomElement(geo.europe.germany)
const pickCityFrance = () => randomElement(geo.europe.france)
const pickCityItaly = () => randomElement(geo.europe.italy)
const pickCityIndia = () => randomElement(geo.asia.india)
const pickCityChina = () => randomElement(geo.asia.china)
const pickCityNepal = () => randomElement(geo.asia.nepal)pickCity()确实是“令人心烦的类型”,还是我误解了这个概念?
更新
在下面@Bergie的回答之后,我意识到类型记录的enum很可能是键入pickCity()参数的适当解决方案,所以我在这里做了一个存根,但是下面,这仍然不是一个完全的解决方案。
我首先创建了两个enum,一个用于大陆,另一个用于国家:
// typescript
enum Continent {
Europe = "europe",
Asia = "asia"
}
enum Country {
Germany = "germany",
France = "france",
Italy = "italy",
India = "india",
China = "china",
Nepal = "nepal"
}然而,正如@Bergi所写的,它们是相互依赖的,因为geo数据的结构方式。所以,我现在解决这个问题的唯一方法是输入any,这肯定不是我想要的解决方案:
type Geo = Record<Continent, any> // <~-~-~-~-~ `any` is :(
const geo: Geo = {
europe: {
germany: ['berlin', 'hamburg', 'cologne'],
france: ['toulouse', 'paris', 'limoges'],
italy: ['rome', 'venice', 'genoa'],
},
asia: {
india: ['mumbai', 'rajkot', 'pune'],
china: ['shenzhen', 'beijing', 'shanghai'],
nepal: ['kohalpur', 'ghorahi', 'hetauda'],
},
};
const randomElement = (arr) => arr[Math.floor(Math.random() * arr.length)];
const pickCity2 = (continent: Continent, country: Country) => randomElement(geo[continent][country])
// calling pickCity2()
console.log(pickCity2(Continent.Europe, Country.Germany)) // => one German city at random为什么我们不能简单地通过更改geo**?**来解开依赖关系
@Bergi问这个问题,因为这似乎是一种不必要的并发症。因此,如果我们有以下的geoSimpler,生活就会更容易一些:
type GeoSimpler = Record<Country, string[]>;
const geoSimpler: GeoSimpler = {
germany: ['berlin', 'hamburg', 'cologne'],
france: ['toulouse', 'paris', 'limoges'],
italy: ['rome', 'venice', 'genoa'],
india: ['mumbai', 'rajkot', 'pune'],
china: ['shenzhen', 'beijing', 'shanghai'],
nepal: ['kohalpur', 'ghorahi', 'hetauda'],
};
const pickCity3 = (country: Country) => randomElement(geoSimpler[country])
console.log(pickCity3(Country.France)) // 不过,!
我仍然想说明不能简化的数据结构。例如,考虑geoTwinCitiesAttractions
const geoTwinCitiesAttractions = {
us: {
cairo: ['U.S. Custom House', 'Cairo Public LIbrary', 'Magnolia Manor'],
memphis: ['Graceland', 'National Civil Rights Museum', 'Beale Street'],
saintPetersburg: ['The Dali Museum', 'Sunken Gardens', 'Chihuly Collection'],
moscow: [],
athens: ['Pleasant Hill Vineyards', 'Little Fish Brewing', 'Athens Farmers Market'],
},
greece: {
athens: ['Acropolis of Athens', 'Parthenon', 'Mount Lycabettus'],
},
france: {
paris: ['Eiffel Tower', 'Louvre Museum', 'Arc de Triomphe'],
},
russia: {
saintPetersburg: ['State Hermitage Museum', 'Savior on the Spilled Blood', 'Winter Palace',
],
moscow: ['Red Square', 'Bolshoi Theatre', 'Cathedral of Christ the Saviour'],
},
egypt: {
cairo: ['Giza Necropolis', 'Mosque of Muhammad Ali', 'Salah Al-Din Al-Ayoubi Castle'],
memphis: ['foo', 'bar', 'baz'],
},
};在这里,我们必须指明国家和城市,因为在不同的国家有同名的城市.那么,我们如何使用enum来避免“严重输入”pickAttraction()呢?
const pickAttraction = (country: string, city: string) => randomElement(geoTwinCitiesAttractions[country][city])发布于 2022-05-15 21:40:47
是的,如果您真的考虑将任意字符串传递给pickCity,那么是“非常类型的”。pickCity('africa', 'sudan')在当前数据结构中失败。更糟糕的是,pickCity('sun', 'earth')、pickCity('major:Scholz', 'population:>10000')或pickCity('','ivqu ioqwe h')根本就没有意义。
但是,如果不将任意字符串传递给它,只将大陆名称传递给第一个参数,而只将状态名称传递给第一个参数,则没关系。使用枚举类型将更适合于键入这些参数。但是,由于您具体询问的是JavaScript,所以没有枚举类型(也没有类型声明),如果需要动态选择选项,那么在运行时使用字符串的是最可行的解决方案。但是您的心智模型(以及注释和文档)必须将它们视为枚举,或者作为一组允许的字符串。
(另一个与“字体”无关的问题是,参数相互依赖。pickCity('america', 'germany')不起作用,因为德国不在美国。你真的需要这块大陆吗?)
https://stackoverflow.com/questions/72251993
复制相似问题